Loading core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +103 −2 Original line number Diff line number Diff line Loading @@ -21,11 +21,14 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; import java.util.Arrays; import java.util.List; import java.util.Objects; Loading @@ -40,6 +43,8 @@ public final class IkeSessionParamsUtils { private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY"; private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY"; private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY"; private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; Loading Loading @@ -71,13 +76,18 @@ public final class IkeSessionParamsUtils { REMOTE_ID_KEY, IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification())); result.putPersistableBundle( LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig())); result.putPersistableBundle( REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig())); result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis()); result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); // TODO: Handle authentication configuration, configuration requests and IKE options. // TODO: Handle configuration requests and IKE options. return result; } Loading Loading @@ -107,14 +117,105 @@ public final class IkeSessionParamsUtils { IkeIdentificationUtils.fromPersistableBundle( in.getPersistableBundle(REMOTE_ID_KEY))); AuthConfigUtils.setBuilderByReadingPersistableBundle( in.getPersistableBundle(LOCAL_AUTH_KEY), in.getPersistableBundle(REMOTE_AUTH_KEY), builder); builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY)); builder.setLifetimeSeconds( in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); // TODO: Handle authentication configuration, configuration requests and IKE options. // TODO: Handle configuration requests and IKE options. return builder.build(); } private static final class AuthConfigUtils { private static final int IKE_AUTH_METHOD_PSK = 1; private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2; private static final int IKE_AUTH_METHOD_EAP = 3; private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY"; @NonNull public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) { if (authConfig instanceof IkeAuthPskConfig) { IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig; return IkeAuthPskConfigUtils.toPersistableBundle( config, createPersistableBundle(IKE_AUTH_METHOD_PSK)); } else { throw new IllegalStateException("Invalid IkeAuthConfig subclass"); } // TODO: Handle EAP auth and digital signature based auth. } private static PersistableBundle createPersistableBundle(int type) { final PersistableBundle result = new PersistableBundle(); result.putInt(AUTH_METHOD_KEY, type); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder) { Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY); final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY); switch (localMethodType) { case IKE_AUTH_METHOD_PSK: if (remoteMethodType != IKE_AUTH_METHOD_PSK) { throw new IllegalArgumentException( "Expect remote auth method to be PSK based, but was " + remoteMethodType); } IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle( localAuthBundle, remoteAuthBundle, builder); break; default: throw new IllegalArgumentException( "Invalid EAP method type " + localMethodType); } // TODO: Handle EAP auth and digital signature based auth. } } private static final class IkeAuthPskConfigUtils { private static final String PSK_KEY = "PSK_KEY"; @NonNull public static PersistableBundle toPersistableBundle( @NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) { result.putPersistableBundle( PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk())); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder) { Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY); final PersistableBundle remotePskBundle = remoteAuthBundle.getPersistableBundle(PSK_KEY); Objects.requireNonNull(localAuthBundle, "Local PSK was null"); Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null"); final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle); final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle); if (!Arrays.equals(localPsk, remotePsk)) { throw new IllegalArgumentException("Local PSK and remote PSK are different"); } builder.setAuthPsk(localPsk); } } } tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.net.vcn.persistablebundleutils; import static org.junit.Assert.assertEquals; import android.net.InetAddresses; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSessionParams; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class IkeSessionParamsUtilsTest { private static IkeSessionParams.Builder createBuilderMinimum() { final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); return new IkeSessionParams.Builder() .setServerHostname(serverAddress.getHostAddress()) .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal()) .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) .setAuthPsk("psk".getBytes()); } private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) { final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params); final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle); assertEquals(result, params); } @Test public void testEncodeRecodeParamsWithLifetimes() throws Exception { final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L); final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L); final IkeSessionParams params = createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithDpdDelay() throws Exception { final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L); final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithNattKeepalive() throws Exception { final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L); final IkeSessionParams params = createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception { final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500}; final IkeSessionParams params = createBuilderMinimum() .setRetransmissionTimeoutsMillis(retransmissionTimeout) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithAuthPsk() throws Exception { final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } } tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java +17 −13 Original line number Diff line number Diff line Loading @@ -32,10 +32,9 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class SaProposalUtilsTest { @Test public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { final IkeSaProposal proposal = new IkeSaProposal.Builder() /** Package private so that IkeSessionParamsUtilsTest can use it */ static IkeSaProposal buildTestIkeSaProposal() { return new IkeSaProposal.Builder() .addEncryptionAlgorithm( SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED) .addEncryptionAlgorithm( Loading @@ -47,6 +46,11 @@ public class SaProposalUtilsTest { .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP) .build(); } @Test public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { final IkeSaProposal proposal = buildTestIkeSaProposal(); final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal); final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle); Loading Loading
core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +103 −2 Original line number Diff line number Diff line Loading @@ -21,11 +21,14 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig; import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; import java.util.Arrays; import java.util.List; import java.util.Objects; Loading @@ -40,6 +43,8 @@ public final class IkeSessionParamsUtils { private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY"; private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY"; private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY"; private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY"; private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; Loading Loading @@ -71,13 +76,18 @@ public final class IkeSessionParamsUtils { REMOTE_ID_KEY, IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification())); result.putPersistableBundle( LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig())); result.putPersistableBundle( REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig())); result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis()); result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds()); result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds()); // TODO: Handle authentication configuration, configuration requests and IKE options. // TODO: Handle configuration requests and IKE options. return result; } Loading Loading @@ -107,14 +117,105 @@ public final class IkeSessionParamsUtils { IkeIdentificationUtils.fromPersistableBundle( in.getPersistableBundle(REMOTE_ID_KEY))); AuthConfigUtils.setBuilderByReadingPersistableBundle( in.getPersistableBundle(LOCAL_AUTH_KEY), in.getPersistableBundle(REMOTE_AUTH_KEY), builder); builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY)); builder.setLifetimeSeconds( in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY)); builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY)); // TODO: Handle authentication configuration, configuration requests and IKE options. // TODO: Handle configuration requests and IKE options. return builder.build(); } private static final class AuthConfigUtils { private static final int IKE_AUTH_METHOD_PSK = 1; private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2; private static final int IKE_AUTH_METHOD_EAP = 3; private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY"; @NonNull public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) { if (authConfig instanceof IkeAuthPskConfig) { IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig; return IkeAuthPskConfigUtils.toPersistableBundle( config, createPersistableBundle(IKE_AUTH_METHOD_PSK)); } else { throw new IllegalStateException("Invalid IkeAuthConfig subclass"); } // TODO: Handle EAP auth and digital signature based auth. } private static PersistableBundle createPersistableBundle(int type) { final PersistableBundle result = new PersistableBundle(); result.putInt(AUTH_METHOD_KEY, type); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder) { Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY); final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY); switch (localMethodType) { case IKE_AUTH_METHOD_PSK: if (remoteMethodType != IKE_AUTH_METHOD_PSK) { throw new IllegalArgumentException( "Expect remote auth method to be PSK based, but was " + remoteMethodType); } IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle( localAuthBundle, remoteAuthBundle, builder); break; default: throw new IllegalArgumentException( "Invalid EAP method type " + localMethodType); } // TODO: Handle EAP auth and digital signature based auth. } } private static final class IkeAuthPskConfigUtils { private static final String PSK_KEY = "PSK_KEY"; @NonNull public static PersistableBundle toPersistableBundle( @NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) { result.putPersistableBundle( PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk())); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder) { Objects.requireNonNull(localAuthBundle, "localAuthBundle was null"); Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null"); final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY); final PersistableBundle remotePskBundle = remoteAuthBundle.getPersistableBundle(PSK_KEY); Objects.requireNonNull(localAuthBundle, "Local PSK was null"); Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null"); final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle); final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle); if (!Arrays.equals(localPsk, remotePsk)) { throw new IllegalArgumentException("Local PSK and remote PSK are different"); } builder.setAuthPsk(localPsk); } } }
tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.net.vcn.persistablebundleutils; import static org.junit.Assert.assertEquals; import android.net.InetAddresses; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSessionParams; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest public class IkeSessionParamsUtilsTest { private static IkeSessionParams.Builder createBuilderMinimum() { final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100"); return new IkeSessionParams.Builder() .setServerHostname(serverAddress.getHostAddress()) .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal()) .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net")) .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net")) .setAuthPsk("psk".getBytes()); } private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) { final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params); final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle); assertEquals(result, params); } @Test public void testEncodeRecodeParamsWithLifetimes() throws Exception { final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L); final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L); final IkeSessionParams params = createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithDpdDelay() throws Exception { final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L); final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithNattKeepalive() throws Exception { final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L); final IkeSessionParams params = createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception { final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500}; final IkeSessionParams params = createBuilderMinimum() .setRetransmissionTimeoutsMillis(retransmissionTimeout) .build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } @Test public void testEncodeRecodeParamsWithAuthPsk() throws Exception { final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build(); verifyPersistableBundleEncodeDecodeIsLossless(params); } }
tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java +17 −13 Original line number Diff line number Diff line Loading @@ -32,10 +32,9 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class SaProposalUtilsTest { @Test public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { final IkeSaProposal proposal = new IkeSaProposal.Builder() /** Package private so that IkeSessionParamsUtilsTest can use it */ static IkeSaProposal buildTestIkeSaProposal() { return new IkeSaProposal.Builder() .addEncryptionAlgorithm( SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED) .addEncryptionAlgorithm( Loading @@ -47,6 +46,11 @@ public class SaProposalUtilsTest { .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP) .build(); } @Test public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { final IkeSaProposal proposal = buildTestIkeSaProposal(); final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal); final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle); Loading