mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-03 00:00:24 -04:00
android: Add ManagedConfigurationService and related classes
Add service that provides access to managed configurations.
This commit is contained in:
parent
c2007d5b09
commit
8796e9bb31
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Tobias Brunner
|
||||
* Copyright (C) 2023 Relution GmbH
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
package org.strongswan.android.data;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.strongswan.android.utils.Constants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class ManagedConfiguration
|
||||
{
|
||||
private static final String KEY_ALLOW_PROFILE_CREATE = "allow_profile_create";
|
||||
private static final String KEY_ALLOW_PROFILE_IMPORT = "allow_profile_import";
|
||||
private static final String KEY_ALLOW_EXISTING_PROFILES = "allow_existing_profiles";
|
||||
private static final String KEY_ALLOW_CERTIFICATE_IMPORT = "allow_certificate_import";
|
||||
private static final String KEY_ALLOW_SETTINGS_ACCESS = "allow_settings_access";
|
||||
private static final String KEY_MANAGED_PROFILES = "managed_profiles";
|
||||
|
||||
private final boolean mAllowProfileCreation;
|
||||
private final boolean mAllowProfileImport;
|
||||
private final boolean mAllowExistingProfiles;
|
||||
private final boolean mAllowCertificateImport;
|
||||
|
||||
private final boolean mAllowSettingsAccess;
|
||||
private final String mDefaultVpnProfile;
|
||||
private final boolean mIgnoreBatteryOptimizations;
|
||||
|
||||
private final Map<String, ManagedVpnProfile> mManagedVpnProfiles;
|
||||
|
||||
ManagedConfiguration()
|
||||
{
|
||||
mAllowProfileCreation = true;
|
||||
mAllowProfileImport = true;
|
||||
mAllowExistingProfiles = true;
|
||||
mAllowCertificateImport = true;
|
||||
|
||||
mAllowSettingsAccess = true;
|
||||
mDefaultVpnProfile = null;
|
||||
mIgnoreBatteryOptimizations = false;
|
||||
|
||||
mManagedVpnProfiles = Collections.emptyMap();
|
||||
}
|
||||
|
||||
ManagedConfiguration(final Bundle bundle)
|
||||
{
|
||||
mAllowProfileCreation = bundle.getBoolean(KEY_ALLOW_PROFILE_CREATE, true);
|
||||
mAllowProfileImport = bundle.getBoolean(KEY_ALLOW_PROFILE_IMPORT, true);
|
||||
mAllowExistingProfiles = bundle.getBoolean(KEY_ALLOW_EXISTING_PROFILES, true);
|
||||
mAllowCertificateImport = bundle.getBoolean(KEY_ALLOW_CERTIFICATE_IMPORT, true);
|
||||
|
||||
mAllowSettingsAccess = bundle.getBoolean(KEY_ALLOW_SETTINGS_ACCESS, true);
|
||||
mDefaultVpnProfile = bundle.getString(Constants.PREF_DEFAULT_VPN_PROFILE, null);
|
||||
mIgnoreBatteryOptimizations = bundle.getBoolean(Constants.PREF_IGNORE_POWER_WHITELIST, false);
|
||||
|
||||
final List<Bundle> managedProfileBundles = getBundleArrayList(bundle, KEY_MANAGED_PROFILES);
|
||||
mManagedVpnProfiles = new HashMap<>(managedProfileBundles.size());
|
||||
|
||||
for (final Bundle managedProfileBundle : managedProfileBundles)
|
||||
{
|
||||
addManagedProfile(managedProfileBundle);
|
||||
}
|
||||
}
|
||||
|
||||
private void addManagedProfile(Bundle managedProfileBundle)
|
||||
{
|
||||
UUID uuid;
|
||||
try
|
||||
{
|
||||
uuid = UUID.fromString(managedProfileBundle.getString(VpnProfileDataSource.KEY_UUID));
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (mManagedVpnProfiles.containsKey(uuid.toString()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final ManagedVpnProfile vpnProfile = new ManagedVpnProfile(managedProfileBundle, uuid);
|
||||
mManagedVpnProfiles.put(uuid.toString(), vpnProfile);
|
||||
}
|
||||
|
||||
private List<Bundle> getBundleArrayList(final Bundle bundle, final String key)
|
||||
{
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
|
||||
{
|
||||
return getBundleArrayListCompat(bundle, key);
|
||||
}
|
||||
|
||||
final Bundle[] bundles = bundle.getParcelableArray(key, Bundle.class);
|
||||
if (bundles == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.asList(bundles);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static List<Bundle> getBundleArrayListCompat(final Bundle bundle, final String key)
|
||||
{
|
||||
final Parcelable[] parcelables = bundle.getParcelableArray(key);
|
||||
if (parcelables == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Bundle[] bundles = Arrays.copyOf(parcelables, parcelables.length, Bundle[].class);
|
||||
return Arrays.asList(bundles);
|
||||
}
|
||||
|
||||
public boolean isAllowProfileCreation()
|
||||
{
|
||||
return mAllowProfileCreation;
|
||||
}
|
||||
|
||||
public boolean isAllowProfileImport()
|
||||
{
|
||||
return mAllowProfileImport;
|
||||
}
|
||||
|
||||
public boolean isAllowExistingProfiles()
|
||||
{
|
||||
return mAllowExistingProfiles;
|
||||
}
|
||||
|
||||
public boolean isAllowCertificateImport()
|
||||
{
|
||||
return mAllowCertificateImport;
|
||||
}
|
||||
|
||||
public boolean isAllowSettingsAccess()
|
||||
{
|
||||
return mAllowSettingsAccess;
|
||||
}
|
||||
|
||||
public String getDefaultVpnProfile()
|
||||
{
|
||||
if (mDefaultVpnProfile != null && mDefaultVpnProfile.equalsIgnoreCase("mru"))
|
||||
{
|
||||
return Constants.PREF_DEFAULT_VPN_PROFILE_MRU;
|
||||
}
|
||||
return mDefaultVpnProfile;
|
||||
}
|
||||
|
||||
public boolean isIgnoreBatteryOptimizations()
|
||||
{
|
||||
return mIgnoreBatteryOptimizations;
|
||||
}
|
||||
|
||||
public Map<String, ManagedVpnProfile> getVpnProfiles()
|
||||
{
|
||||
return mManagedVpnProfiles;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Relution GmbH
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
package org.strongswan.android.data;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.RestrictionsManager;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.strongswan.android.utils.Constants;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class ManagedConfigurationService
|
||||
{
|
||||
private final Context mContext;
|
||||
|
||||
private ManagedConfiguration mManagedConfiguration = new ManagedConfiguration();
|
||||
private Map<String, ManagedVpnProfile> mManagedVpnProfiles = Collections.emptyMap();
|
||||
|
||||
public ManagedConfigurationService(final Context context)
|
||||
{
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
public void loadConfiguration()
|
||||
{
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final RestrictionsManager restrictionsService = mContext.getSystemService(RestrictionsManager.class);
|
||||
if (restrictionsService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Bundle configuration = restrictionsService.getApplicationRestrictions();
|
||||
if (configuration == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final ManagedConfiguration managedConfiguration = new ManagedConfiguration(configuration);
|
||||
mManagedConfiguration = managedConfiguration;
|
||||
mManagedVpnProfiles = managedConfiguration.getVpnProfiles();
|
||||
}
|
||||
|
||||
public void updateSettings()
|
||||
{
|
||||
if (!mManagedConfiguration.isAllowSettingsAccess())
|
||||
{
|
||||
final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
final SharedPreferences.Editor editor = pref.edit();
|
||||
editor.putBoolean(Constants.PREF_IGNORE_POWER_WHITELIST, mManagedConfiguration.isIgnoreBatteryOptimizations());
|
||||
editor.putString(Constants.PREF_DEFAULT_VPN_PROFILE, mManagedConfiguration.getDefaultVpnProfile());
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
||||
public ManagedConfiguration getManagedConfiguration()
|
||||
{
|
||||
return mManagedConfiguration;
|
||||
}
|
||||
|
||||
public Map<String, ManagedVpnProfile> getManagedProfiles()
|
||||
{
|
||||
return mManagedVpnProfiles;
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Relution GmbH
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
package org.strongswan.android.data;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.strongswan.android.utils.Constants;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ManagedVpnProfile extends VpnProfile
|
||||
{
|
||||
private static final String KEY_REMOTE = "remote";
|
||||
private static final String KEY_LOCAL = "local";
|
||||
private static final String KEY_INCLUDED_APPS = "included_apps";
|
||||
private static final String KEY_EXCLUDED_APPS = "excluded_apps";
|
||||
|
||||
private static final String KEY_TRANSPORT_IPV6_FLAG = "transport_ipv6";
|
||||
private static final String KEY_REMOTE_CERT_REQ_FLAG = "remote_cert_req";
|
||||
private static final String KEY_REMOTE_REVOCATION_CRL_FLAG = "remote_revocation_crl";
|
||||
private static final String KEY_REMOTE_REVOCATION_OCSP_FLAG = "remote_revocation_ocsp";
|
||||
private static final String KEY_REMOTE_REVOCATION_STRICT_FLAG = "remote_revocation_strict";
|
||||
private static final String KEY_LOCAL_RSA_PSS_FLAG = "local_rsa_pss";
|
||||
|
||||
private static final String KEY_SPLIT_TUNNELLING_BLOCK_IPV4_FLAG = "split_tunnelling_block_ipv4";
|
||||
private static final String KEY_SPLIT_TUNNELLING_BLOCK_IPV6_FLAG = "split_tunnelling_block_ipv6";
|
||||
|
||||
ManagedVpnProfile(final Bundle bundle, final UUID uuid)
|
||||
{
|
||||
int flags = 0;
|
||||
int splitFlags = 0;
|
||||
|
||||
setReadOnly(true);
|
||||
setUUID(uuid);
|
||||
setName(bundle.getString(VpnProfileDataSource.KEY_NAME));
|
||||
setVpnType(VpnType.fromIdentifier(bundle.getString(VpnProfileDataSource.KEY_VPN_TYPE)));
|
||||
|
||||
final Bundle remote = bundle.getBundle(KEY_REMOTE);
|
||||
if (remote != null)
|
||||
{
|
||||
setGateway(remote.getString(VpnProfileDataSource.KEY_GATEWAY));
|
||||
setPort(getInt(remote, VpnProfileDataSource.KEY_PORT, 1, 65535));
|
||||
setRemoteId(remote.getString(VpnProfileDataSource.KEY_REMOTE_ID));
|
||||
setCertificateAlias(remote.getString(VpnProfileDataSource.KEY_CERTIFICATE));
|
||||
|
||||
flags = addNegativeFlag(flags, remote, KEY_REMOTE_CERT_REQ_FLAG, VpnProfile.FLAGS_SUPPRESS_CERT_REQS);
|
||||
flags = addNegativeFlag(flags, remote, KEY_REMOTE_REVOCATION_CRL_FLAG, VpnProfile.FLAGS_DISABLE_CRL);
|
||||
flags = addNegativeFlag(flags, remote, KEY_REMOTE_REVOCATION_OCSP_FLAG, VpnProfile.FLAGS_DISABLE_OCSP);
|
||||
flags = addPositiveFlag(flags, remote, KEY_REMOTE_REVOCATION_STRICT_FLAG, VpnProfile.FLAGS_STRICT_REVOCATION);
|
||||
}
|
||||
|
||||
final Bundle local = bundle.getBundle(KEY_LOCAL);
|
||||
if (local != null)
|
||||
{
|
||||
setLocalId(local.getString(VpnProfileDataSource.KEY_LOCAL_ID));
|
||||
setUsername(local.getString(VpnProfileDataSource.KEY_USERNAME));
|
||||
|
||||
flags = addPositiveFlag(flags, local, KEY_LOCAL_RSA_PSS_FLAG, VpnProfile.FLAGS_RSA_PSS);
|
||||
}
|
||||
|
||||
final String includedPackageNames = bundle.getString(KEY_INCLUDED_APPS);
|
||||
final String excludedPackageNames = bundle.getString(KEY_EXCLUDED_APPS);
|
||||
|
||||
if (!TextUtils.isEmpty(includedPackageNames))
|
||||
{
|
||||
setSelectedAppsHandling(VpnProfile.SelectedAppsHandling.SELECTED_APPS_ONLY);
|
||||
setSelectedApps(includedPackageNames);
|
||||
}
|
||||
else if (!TextUtils.isEmpty(excludedPackageNames))
|
||||
{
|
||||
setSelectedAppsHandling(VpnProfile.SelectedAppsHandling.SELECTED_APPS_EXCLUDE);
|
||||
setSelectedApps(excludedPackageNames);
|
||||
}
|
||||
|
||||
setMTU(getInt(bundle, VpnProfileDataSource.KEY_MTU, Constants.MTU_MIN, Constants.MTU_MAX));
|
||||
setNATKeepAlive(getInt(bundle, VpnProfileDataSource.KEY_NAT_KEEPALIVE, Constants.NAT_KEEPALIVE_MIN, Constants.NAT_KEEPALIVE_MAX));
|
||||
setIkeProposal(bundle.getString(VpnProfileDataSource.KEY_IKE_PROPOSAL));
|
||||
setEspProposal(bundle.getString(VpnProfileDataSource.KEY_ESP_PROPOSAL));
|
||||
setDnsServers(bundle.getString(VpnProfileDataSource.KEY_DNS_SERVERS));
|
||||
flags = addPositiveFlag(flags, bundle, KEY_TRANSPORT_IPV6_FLAG, VpnProfile.FLAGS_IPv6_TRANSPORT);
|
||||
|
||||
final Bundle splitTunneling = bundle.getBundle(VpnProfileDataSource.KEY_SPLIT_TUNNELING);
|
||||
if (splitTunneling != null)
|
||||
{
|
||||
splitFlags = addPositiveFlag(splitFlags, splitTunneling, KEY_SPLIT_TUNNELLING_BLOCK_IPV4_FLAG, VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4);
|
||||
splitFlags = addPositiveFlag(splitFlags, splitTunneling, KEY_SPLIT_TUNNELLING_BLOCK_IPV6_FLAG, VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6);
|
||||
|
||||
setExcludedSubnets(splitTunneling.getString(VpnProfileDataSource.KEY_EXCLUDED_SUBNETS));
|
||||
setIncludedSubnets(splitTunneling.getString(VpnProfileDataSource.KEY_INCLUDED_SUBNETS));
|
||||
}
|
||||
|
||||
setSplitTunneling(splitFlags);
|
||||
setFlags(flags);
|
||||
}
|
||||
|
||||
private static Integer getInt(final Bundle bundle, final String key, final int min, final int max)
|
||||
{
|
||||
final int value = bundle.getInt(key);
|
||||
return value < min || value > max ? null : value;
|
||||
}
|
||||
|
||||
private static int addPositiveFlag(int flags, Bundle bundle, String key, int flag)
|
||||
{
|
||||
if (bundle.getBoolean(key))
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static int addNegativeFlag(int flags, Bundle bundle, String key, int flag)
|
||||
{
|
||||
if (!bundle.getBoolean(key))
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user