All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.security.net.config.ApplicationConfig Maven / Gradle / Ivy

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.security.net.config;

import android.util.Pair;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import javax.net.ssl.X509TrustManager;

/**
 * An application's network security configuration.
 *
 * 

{@link #getConfigForHostname(String)} provides a means to obtain network security * configuration to be used for communicating with a specific hostname.

* * @hide */ public final class ApplicationConfig { private static ApplicationConfig sInstance; private static Object sLock = new Object(); private Set> mConfigs; private NetworkSecurityConfig mDefaultConfig; private X509TrustManager mTrustManager; private ConfigSource mConfigSource; private boolean mInitialized; private final Object mLock = new Object(); public ApplicationConfig(ConfigSource configSource) { mConfigSource = configSource; mInitialized = false; } /** * @hide */ public boolean hasPerDomainConfigs() { ensureInitialized(); return mConfigs != null && !mConfigs.isEmpty(); } /** * Get the {@link NetworkSecurityConfig} corresponding to the provided hostname. * When matching the most specific matching domain rule will be used, if no match exists * then the default configuration will be returned. * * {@code NetworkSecurityConfig} objects returned by this method can be safely cached for * {@code hostname}. Subsequent calls with the same hostname will always return the same * {@code NetworkSecurityConfig}. * * @return {@link NetworkSecurityConfig} to be used to determine * the network security configuration for connections to {@code hostname}. */ public NetworkSecurityConfig getConfigForHostname(String hostname) { ensureInitialized(); if (hostname == null || hostname.isEmpty() || mConfigs == null) { return mDefaultConfig; } if (hostname.charAt(0) == '.') { throw new IllegalArgumentException("hostname must not begin with a ."); } // Domains are case insensitive. hostname = hostname.toLowerCase(Locale.US); // Normalize hostname by removing trailing . if present, all Domain hostnames are // absolute. if (hostname.charAt(hostname.length() - 1) == '.') { hostname = hostname.substring(0, hostname.length() - 1); } // Find the Domain -> NetworkSecurityConfig entry with the most specific matching // Domain entry for hostname. // TODO: Use a smarter data structure for the lookup. Pair bestMatch = null; for (Pair entry : mConfigs) { Domain domain = entry.first; NetworkSecurityConfig config = entry.second; // Check for an exact match. if (domain.hostname.equals(hostname)) { return config; } // Otherwise check if the Domain includes sub-domains and that the hostname is a // sub-domain of the Domain. if (domain.subdomainsIncluded && hostname.endsWith(domain.hostname) && hostname.charAt(hostname.length() - domain.hostname.length() - 1) == '.') { if (bestMatch == null) { bestMatch = entry; } else if (domain.hostname.length() > bestMatch.first.hostname.length()) { bestMatch = entry; } } } if (bestMatch != null) { return bestMatch.second; } // If no match was found use the default configuration. return mDefaultConfig; } /** * Returns the {@link X509TrustManager} that implements the checking of trust anchors and * certificate pinning based on this configuration. */ public X509TrustManager getTrustManager() { ensureInitialized(); return mTrustManager; } /** * Returns {@code true} if cleartext traffic is permitted for this application, which is the * case only if all configurations permit cleartext traffic. For finer-grained policy use * {@link #isCleartextTrafficPermitted(String)}. */ public boolean isCleartextTrafficPermitted() { ensureInitialized(); if (mConfigs != null) { for (Pair entry : mConfigs) { if (!entry.second.isCleartextTrafficPermitted()) { return false; } } } return mDefaultConfig.isCleartextTrafficPermitted(); } /** * Returns {@code true} if cleartext traffic is permitted for this application when connecting * to {@code hostname}. */ public boolean isCleartextTrafficPermitted(String hostname) { return getConfigForHostname(hostname).isCleartextTrafficPermitted(); } public void handleTrustStorageUpdate() { synchronized(mLock) { // If the config is uninitialized then there is no work to be done to handle an update, // avoid needlessly parsing configs. if (!mInitialized) { return; } mDefaultConfig.handleTrustStorageUpdate(); if (mConfigs != null) { Set updatedConfigs = new HashSet(mConfigs.size()); for (Pair entry : mConfigs) { if (updatedConfigs.add(entry.second)) { entry.second.handleTrustStorageUpdate(); } } } } } private void ensureInitialized() { synchronized(mLock) { if (mInitialized) { return; } mConfigs = mConfigSource.getPerDomainConfigs(); mDefaultConfig = mConfigSource.getDefaultConfig(); mConfigSource = null; mTrustManager = new RootTrustManager(this); mInitialized = true; } } public static void setDefaultInstance(ApplicationConfig config) { synchronized (sLock) { sInstance = config; } } public static ApplicationConfig getDefaultInstance() { synchronized (sLock) { return sInstance; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy