1 /* 2 * Copyright (C) 2010, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.connectivitymanagertest; 18 19 import android.net.IpConfiguration.IpAssignment; 20 import android.net.IpConfiguration.ProxySettings; 21 import android.net.LinkAddress; 22 import android.net.StaticIpConfiguration; 23 import android.net.wifi.WifiConfiguration; 24 import android.net.wifi.WifiConfiguration.AuthAlgorithm; 25 import android.net.wifi.WifiConfiguration.KeyMgmt; 26 import android.net.wifi.WifiEnterpriseConfig; 27 28 import org.json.JSONArray; 29 import org.json.JSONException; 30 import org.json.JSONObject; 31 32 import java.net.InetAddress; 33 import java.net.UnknownHostException; 34 import java.util.ArrayList; 35 import java.util.List; 36 37 /** 38 * Helper for dealing with creating {@link WifiConfiguration} objects. 39 */ 40 public class WifiConfigurationHelper { 41 private static final int NONE = 0; 42 private static final int WEP = 1; 43 private static final int PSK = 2; 44 private static final int EAP = 3; 45 46 /** 47 * Private constructor since this a static class. 48 */ WifiConfigurationHelper()49 private WifiConfigurationHelper() {} 50 51 /** 52 * Create a {@link WifiConfiguration} for an open network 53 * 54 * @param ssid The SSID of the wifi network 55 * @return The {@link WifiConfiguration} 56 */ createOpenConfig(String ssid)57 public static WifiConfiguration createOpenConfig(String ssid) { 58 WifiConfiguration config = createGenericConfig(ssid); 59 60 config.allowedKeyManagement.set(KeyMgmt.NONE); 61 return config; 62 } 63 64 /** 65 * Create a {@link WifiConfiguration} for a WEP secured network 66 * 67 * @param ssid The SSID of the wifi network 68 * @param password Either a 10, 26, or 58 character hex string or the plain text password 69 * @return The {@link WifiConfiguration} 70 */ createWepConfig(String ssid, String password)71 public static WifiConfiguration createWepConfig(String ssid, String password) { 72 WifiConfiguration config = createGenericConfig(ssid); 73 74 if (isHex(password, 10) || isHex(password, 26) || isHex(password, 58)) { 75 config.wepKeys[0] = password; 76 } else { 77 config.wepKeys[0] = quotedString(password); 78 } 79 80 config.allowedKeyManagement.set(KeyMgmt.NONE); 81 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); 82 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); 83 return config; 84 } 85 86 /** 87 * Create a {@link WifiConfiguration} for a PSK secured network 88 * 89 * @param ssid The SSID of the wifi network 90 * @param password Either a 64 character hex string or the plain text password 91 * @return The {@link WifiConfiguration} 92 */ createPskConfig(String ssid, String password)93 public static WifiConfiguration createPskConfig(String ssid, String password) { 94 WifiConfiguration config = createGenericConfig(ssid); 95 96 if (isHex(password, 64)) { 97 config.preSharedKey = password; 98 } else { 99 config.preSharedKey = quotedString(password); 100 } 101 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 102 return config; 103 } 104 105 /** 106 * Create a {@link WifiConfiguration} for an EAP secured network 107 * 108 * @param ssid The SSID of the wifi network 109 * @param password The password 110 * @param eapMethod The EAP method 111 * @param phase2 The phase 2 method or null 112 * @param identity The identity or null 113 * @param anonymousIdentity The anonymous identity or null 114 * @param caCert The CA certificate or null 115 * @param clientCert The client certificate or null 116 * @return The {@link WifiConfiguration} 117 */ createEapConfig(String ssid, String password, int eapMethod, Integer phase2, String identity, String anonymousIdentity, String caCert, String clientCert)118 public static WifiConfiguration createEapConfig(String ssid, String password, int eapMethod, 119 Integer phase2, String identity, String anonymousIdentity, String caCert, 120 String clientCert) { 121 WifiConfiguration config = new WifiConfiguration(); 122 config.SSID = quotedString(ssid); 123 124 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 125 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 126 127 // Set defaults 128 if (phase2 == null) phase2 = WifiEnterpriseConfig.Phase2.NONE; 129 if (identity == null) identity = ""; 130 if (anonymousIdentity == null) anonymousIdentity = ""; 131 if (caCert == null) caCert = ""; 132 if (clientCert == null) clientCert = ""; 133 134 config.enterpriseConfig.setPassword(password); 135 config.enterpriseConfig.setEapMethod(eapMethod); 136 config.enterpriseConfig.setPhase2Method(phase2); 137 config.enterpriseConfig.setIdentity(identity); 138 config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity); 139 config.enterpriseConfig.setCaCertificateAlias(caCert); 140 config.enterpriseConfig.setClientCertificateAlias(clientCert); 141 return config; 142 } 143 144 /** 145 * Create a generic {@link WifiConfiguration} used by the other create methods. 146 */ createGenericConfig(String ssid)147 private static WifiConfiguration createGenericConfig(String ssid) { 148 WifiConfiguration config = new WifiConfiguration(); 149 config.SSID = quotedString(ssid); 150 config.setIpAssignment(IpAssignment.DHCP); 151 config.setProxySettings(ProxySettings.NONE); 152 return config; 153 } 154 155 /** 156 * Parse a JSON string for WiFi configurations stored as a JSON string. 157 * <p> 158 * This json string should be a list of dictionaries, with each dictionary containing a single 159 * wifi configuration. The wifi configuration requires the fields "ssid" and "security" with 160 * security being one of NONE, WEP, PSK, or EAP. If WEP, PSK, or EAP are selected, the field 161 * "password" must also be provided. If EAP is selected, then the fiels "eap", "phase2", 162 * "identity", "ananymous_identity", "ca_cert", and "client_cert" are also required. Lastly, 163 * static IP settings are also supported. If the field "ip" is set, then the fields "gateway", 164 * "prefix_length", "dns1", and "dns2" are required. 165 * </p> 166 * @throws IllegalArgumentException if the input string was not valid JSON or if any mandatory 167 * fields are missing. 168 */ parseJson(String in)169 public static List<WifiConfiguration> parseJson(String in) { 170 try { 171 JSONArray jsonConfigs = new JSONArray(in); 172 List<WifiConfiguration> wifiConfigs = new ArrayList<>(jsonConfigs.length()); 173 174 for (int i = 0; i < jsonConfigs.length(); i++) { 175 JSONObject jsonConfig = jsonConfigs.getJSONObject(i); 176 177 wifiConfigs.add(getWifiConfiguration(jsonConfig)); 178 } 179 return wifiConfigs; 180 } catch (JSONException e) { 181 throw new IllegalArgumentException(e); 182 } 183 } 184 185 /** 186 * Parse a {@link JSONObject} and return the wifi configuration. 187 * 188 * @throws IllegalArgumentException if any mandatory fields are missing. 189 */ getWifiConfiguration(JSONObject jsonConfig)190 private static WifiConfiguration getWifiConfiguration(JSONObject jsonConfig) 191 throws JSONException { 192 String ssid = jsonConfig.getString("ssid"); 193 String password = null; 194 WifiConfiguration config; 195 196 int securityType = getSecurityType(jsonConfig.getString("security")); 197 switch (securityType) { 198 case NONE: 199 config = createOpenConfig(ssid); 200 break; 201 case WEP: 202 password = jsonConfig.getString("password"); 203 config = createWepConfig(ssid, password); 204 break; 205 case PSK: 206 password = jsonConfig.getString("password"); 207 config = createPskConfig(ssid, password); 208 break; 209 case EAP: 210 password = jsonConfig.getString("password"); 211 int eapMethod = getEapMethod(jsonConfig.getString("eap")); 212 Integer phase2 = null; 213 if (jsonConfig.has("phase2")) { 214 phase2 = getPhase2(jsonConfig.getString("phase2")); 215 } 216 String identity = null; 217 if (jsonConfig.has("identity")) { 218 identity = jsonConfig.getString("identity"); 219 } 220 String anonymousIdentity = null; 221 if (jsonConfig.has("anonymous_identity")) { 222 anonymousIdentity = jsonConfig.getString("anonymous_identity"); 223 } 224 String caCert = null; 225 if (jsonConfig.has("ca_cert")) { 226 caCert = (jsonConfig.getString("ca_cert")); 227 } 228 String clientCert = null; 229 if (jsonConfig.has("client_cert")) { 230 clientCert = jsonConfig.getString("client_cert"); 231 } 232 config = createEapConfig(ssid, password, eapMethod, phase2, identity, 233 anonymousIdentity, caCert, clientCert); 234 break; 235 default: 236 // Should never reach here as getSecurityType will already throw an exception 237 throw new IllegalArgumentException(); 238 } 239 240 if (jsonConfig.has("ip")) { 241 StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); 242 243 InetAddress ipAddress = getInetAddress(jsonConfig.getString("ip")); 244 int prefixLength = getPrefixLength(jsonConfig.getInt("prefix_length")); 245 staticIpConfig.ipAddress = new LinkAddress(ipAddress, prefixLength); 246 staticIpConfig.gateway = getInetAddress(jsonConfig.getString("gateway")); 247 staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1"))); 248 staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2"))); 249 250 config.setIpAssignment(IpAssignment.STATIC); 251 config.setStaticIpConfiguration(staticIpConfig); 252 } else { 253 config.setIpAssignment(IpAssignment.DHCP); 254 } 255 256 config.setProxySettings(ProxySettings.NONE); 257 return config; 258 } 259 quotedString(String s)260 private static String quotedString(String s) { 261 return String.format("\"%s\"", s); 262 } 263 264 /** 265 * Get the security type from a string. 266 * 267 * @throws IllegalArgumentException if the string is not a supported security type. 268 */ getSecurityType(String security)269 private static int getSecurityType(String security) { 270 if ("NONE".equalsIgnoreCase(security)) { 271 return NONE; 272 } 273 if ("WEP".equalsIgnoreCase(security)) { 274 return WEP; 275 } 276 if ("PSK".equalsIgnoreCase(security)) { 277 return PSK; 278 } 279 if ("EAP".equalsIgnoreCase(security)) { 280 return EAP; 281 } 282 throw new IllegalArgumentException("Security type must be one of NONE, WEP, PSK, or EAP"); 283 } 284 285 /** 286 * Get the EAP method from a string. 287 * 288 * @throws IllegalArgumentException if the string is not a supported EAP method. 289 */ getEapMethod(String eapMethod)290 private static int getEapMethod(String eapMethod) { 291 if ("TLS".equalsIgnoreCase(eapMethod)) { 292 return WifiEnterpriseConfig.Eap.TLS; 293 } 294 if ("TTLS".equalsIgnoreCase(eapMethod)) { 295 return WifiEnterpriseConfig.Eap.TTLS; 296 } 297 if ("PEAP".equalsIgnoreCase(eapMethod)) { 298 return WifiEnterpriseConfig.Eap.PEAP; 299 } 300 throw new IllegalArgumentException("EAP method must be one of TLS, TTLS, or PEAP"); 301 } 302 303 /** 304 * Get the phase 2 method from a string. 305 * 306 * @throws IllegalArgumentException if the string is not a supported phase 2 method. 307 */ getPhase2(String phase2)308 private static int getPhase2(String phase2) { 309 if ("PAP".equalsIgnoreCase(phase2)) { 310 return WifiEnterpriseConfig.Phase2.PAP; 311 } 312 if ("MSCHAP".equalsIgnoreCase(phase2)) { 313 return WifiEnterpriseConfig.Phase2.MSCHAP; 314 } 315 if ("MSCHAPV2".equalsIgnoreCase(phase2)) { 316 return WifiEnterpriseConfig.Phase2.MSCHAPV2; 317 } 318 if ("GTC".equalsIgnoreCase(phase2)) { 319 return WifiEnterpriseConfig.Phase2.GTC; 320 } 321 throw new IllegalArgumentException("Phase2 must be one of PAP, MSCHAP, MSCHAPV2, or GTC"); 322 } 323 324 /** 325 * Get an {@link InetAddress} from a string 326 * 327 * @throws IllegalArgumentException if the string is not a valid IP address. 328 */ getInetAddress(String ipAddress)329 private static InetAddress getInetAddress(String ipAddress) { 330 if (!InetAddress.isNumeric(ipAddress)) { 331 throw new IllegalArgumentException( 332 String.format("IP address %s is not numeric", ipAddress)); 333 } 334 335 try { 336 return InetAddress.getByName(ipAddress); 337 } catch (UnknownHostException e) { 338 throw new IllegalArgumentException( 339 String.format("IP address %s could not be resolved", ipAddress)); 340 } 341 } 342 343 /** 344 * Get the prefix length from an int. 345 * 346 * @throws IllegalArgumentException if the prefix length is less than 0 or greater than 32. 347 */ getPrefixLength(int prefixLength)348 private static int getPrefixLength(int prefixLength) { 349 if (prefixLength < 0 || prefixLength > 32) { 350 throw new IllegalArgumentException("Prefix length cannot be less than 0 or more than 32"); 351 } 352 return prefixLength; 353 } 354 355 /** 356 * Utility method to check if a given string is a hexadecimal string of given length 357 */ isHex(String input, int length)358 public static boolean isHex(String input, int length) { 359 if (input == null || length < 0) { 360 return false; 361 } 362 return input.matches(String.format("[0-9A-Fa-f]{%d}", length)); 363 } 364 } 365