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