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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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