Skip to content

Commit ea24216

Browse files
author
Mohit
authored
Merge branch 'dev' into mchand/openid-issuer-validation
2 parents a7347b5 + 3faf17b commit ea24216

15 files changed

Lines changed: 556 additions & 16 deletions

File tree

changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
vNext
22
----------
33
- [MINOR] Add Open Id configuration issuer validation reporting in OpenIdProviderConfigurationClient (#2751)
4+
- [MINOR] Implement TenantUtil (#2761)
5+
- [MAJOR] Update proguard rules in common (#2756)
6+
- [MINOR] Add query parameter for Android Release OS Version (#2754)
47
- [MINOR] Add client scenario to JwtRequestBody (#2755)
58

69
Version 22.1.0

common/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ dependencies {
174174
implementation "androidx.credentials:credentials-play-services-auth:$rootProject.ext.AndroidCredentialsVersion"
175175
implementation "com.google.android.gms:play-services-fido:$rootProject.ext.LegacyFidoApiVersion"
176176
implementation "com.google.android.libraries.identity.googleid:googleid:$rootProject.ext.GoogleIdVersion"
177+
implementation "com.github.stephenc.jcip:jcip-annotations:$rootProject.ext.jcipAnnotationVersion"
177178

178179
constraints {
179180
implementation ("com.squareup.okio:okio:3.4.0") {

common/consumer-rules.pro

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,33 @@
1717
#}
1818

1919
##---------------Begin: proguard configuration for Common --------
20-
# Intentionally blank, left to consumers of common to implement.
20+
# keep with optmizations and shrinking, but do not obfuscate
21+
-keep,allowoptimization,allowshrinking class !com.microsoft.identity.common.java.nativeauth.**, !com.microsoft.identity.common.nativeauth.**, com.microsoft.identity.** { *; }
22+
-keep class * extends com.microsoft.identity.common.java.authorities.Authority { *; }
23+
-keep class * extends com.microsoft.identity.common.java.authorities.AzureActiveDirectoryAudience { *; }
24+
-keep class * extends com.microsoft.identity.common.java.cache.ICacheRecord { *; }
25+
-keep class * extends com.microsoft.identity.common.java.cache.ITokenCacheItem { *; }
26+
-keep class * extends com.microsoft.identity.common.java.authscheme.AbstractAuthenticationScheme { *; }
27+
-keep class com.microsoft.identity.common.internal.broker.AuthUxJsonPayload { *; }
28+
29+
30+
#For Android Credential Manager: https://developer.android.com/training/sign-in/passkeys#proguard
31+
-if class androidx.credentials.CredentialManager
32+
-keep class androidx.credentials.playservices.** {
33+
*;
34+
}
35+
36+
# Runtime annotations
37+
-keep class net.jcip.annotations.GuardedBy
38+
-keep class net.jcip.annotations.Immutable
39+
-keep class net.jcip.annotations.ThreadSafe
40+
41+
# Compile time annotations
42+
-dontwarn edu.umd.cs.findbugs.annotations.NonNull
43+
-dontwarn edu.umd.cs.findbugs.annotations.Nullable
44+
-dontwarn edu.umd.cs.findbugs.annotations.SuppressFBWarnings
45+
46+
-keepattributes SourceFile,LineNumberTable
2147

2248
##---------------Begin: proguard configuration for Nimbus ----------
2349
# Intentionally blank, left to consumers of common to implement.
@@ -28,7 +54,7 @@
2854
##---------------Begin: proguard configuration for Gson --------
2955
# Gson uses generic type information stored in a class file when working with fields. Proguard
3056
# removes such information by default, so configure it to keep all of it.
31-
-keepattributes Signature
57+
-keepattributes Signature,SourceFile,LineNumberTable
3258

3359
# For using GSON @Expose annotation
3460
-keepattributes *Annotation*
@@ -37,26 +63,27 @@
3763
-dontwarn sun.misc.**
3864
#-keep class com.google.gson.stream.** { *; }
3965

40-
# Application classes that will be serialized/deserialized over Gson
41-
-keep class com.google.gson.examples.android.model.** { <fields>; }
42-
4366
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
4467
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
4568
-keep class * extends com.google.gson.TypeAdapter
4669
-keep class * implements com.google.gson.TypeAdapterFactory
4770
-keep class * implements com.google.gson.JsonSerializer
4871
-keep class * implements com.google.gson.JsonDeserializer
72+
-keep class com.google.gson.reflect.TypeToken { *; }
73+
-keep class * extends com.google.gson.reflect.TypeToken { *; }
4974

75+
##---------------Begin: proguard configuration for OpenTelemetry --------
5076
# keep everything in this package from being removed or renamed
5177
-keep class io.opentelemetry.** { *; }
5278

5379
# Prevent R8 from leaving Data object members always null
54-
-keepclassmembers,allowobfuscation class * {
80+
-keepclassmembers class com.microsoft.identity.** {
5581
@com.google.gson.annotations.SerializedName <fields>;
82+
@com.squareup.moshi.Json <fields>;
5683
}
5784

58-
#For Android Credential Manager: https://developer.android.com/training/sign-in/passkeys#proguard
59-
-if class androidx.credentials.CredentialManager
60-
-keep class androidx.credentials.playservices.** {
61-
*;
62-
}
85+
## Other
86+
# Compile time annotation
87+
-dontwarn com.google.auto.value.AutoValue$CopyAnnotations
88+
-dontwarn com.google.auto.value.AutoValue
89+
-dontwarn com.google.auto.value.extension.memoized.Memoized

common/src/main/java/com/microsoft/identity/common/base64/AndroidBase64.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// THE SOFTWARE.
2323
package com.microsoft.identity.common.base64
2424

25+
import androidx.annotation.Keep
2526
import com.microsoft.identity.common.java.base64.Base64Flags
2627
import com.microsoft.identity.common.java.base64.Base64Util
2728
import com.microsoft.identity.common.java.base64.IBase64
@@ -33,8 +34,9 @@ import com.microsoft.identity.common.java.base64.IBase64
3334
* you'll need to make change in [Base64Util] too.
3435
*
3536
* see [Base64Util] for more info.
37+
* This is called using reflection from [Base64Util], hence the @Keep annotation.
3638
**/
37-
39+
@Keep
3840
class AndroidBase64 : IBase64 {
3941

4042
override fun encode(input: ByteArray, vararg flags: Base64Flags): ByteArray {

common/src/main/java/com/microsoft/identity/common/internal/platform/AndroidDeviceMetadata.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,16 @@ public String getCpu() {
7373

7474
@Override
7575
public @NonNull String getOsForMats() {
76-
return android.os.Build.VERSION.RELEASE;
76+
return getAndroidReleaseOs();
7777
}
7878

7979
@Override
8080
public @NonNull String getOsForDrs() {
81+
return getAndroidReleaseOs();
82+
}
83+
84+
@Override
85+
public @NonNull String getAndroidReleaseOs() {
8186
return android.os.Build.VERSION.RELEASE;
8287
}
8388

common/src/main/java/com/microsoft/identity/common/internal/util/AndroidKeyStoreUtil.java

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555

5656
import edu.umd.cs.findbugs.annotations.Nullable;
5757
import io.opentelemetry.api.common.Attributes;
58+
import io.opentelemetry.api.common.AttributesBuilder;
5859
import io.opentelemetry.api.metrics.LongCounter;
5960
import lombok.NonNull;
6061

@@ -84,6 +85,11 @@ public class AndroidKeyStoreUtil {
8485
*/
8586
private static final String ANDROID_KEY_STORE_TYPE = "AndroidKeyStore";
8687

88+
/**
89+
* Max length of stack trace to search for a keystore exception
90+
*/
91+
private static int KEYSTORE_EXCEPTION_CAUSE_CHAIN_MAX_DEPTH = 20;
92+
8793
private AndroidKeyStoreUtil() {
8894
}
8995

@@ -447,12 +453,11 @@ public static synchronized SecretKey unwrap(@NonNull final byte[] wrappedKeyBlob
447453
exception
448454
);
449455
if (exception instanceof InvalidKeyException) {
450-
final Attributes attributes = Attributes.builder()
456+
final Attributes attributes = createAttributesBuilderFromInvalidKeyException((InvalidKeyException) exception)
451457
.put(AttributeName.keystore_operation.name(), "unwrap")
452458
.put(AttributeName.error_code.name(), errCode)
453-
.put(AttributeName.error_type.name(), clientException.getClass().getSimpleName())
454-
.put(AttributeName.keystore_exception_stack_trace.name(), ThrowableUtil.getStackTraceAsString(clientException))
455459
.build();
460+
456461
sFailedAndroidKeyStoreUnwrapOperationCount.add(1, attributes);
457462
}
458463
Logger.error(
@@ -464,4 +469,65 @@ public static synchronized SecretKey unwrap(@NonNull final byte[] wrappedKeyBlob
464469
throw clientException;
465470
}
466471

472+
/**
473+
* Populate attributes from an InvalidKeyException, attempting to extract details from a nested
474+
* KeyStoreException if available (API Level 33+).
475+
*/
476+
private static AttributesBuilder createAttributesBuilderFromInvalidKeyException(final InvalidKeyException exception) {
477+
String ksMessage;
478+
final String errorType;
479+
final String ksNumericErrorCode;
480+
481+
// Check API Level before attempting to extract KeyStoreException details
482+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
483+
final android.security.KeyStoreException keyStoreException = findKeyStoreException(exception);
484+
if (keyStoreException != null) {
485+
ksMessage = keyStoreException.getMessage();
486+
if (ksMessage == null) {
487+
ksMessage = "Keystore exception found, no error message";
488+
}
489+
errorType = "KeyStoreException";
490+
ksNumericErrorCode = String.valueOf(keyStoreException.getNumericErrorCode());
491+
} else {
492+
ksMessage = "No keystore exception found";
493+
errorType = "InvalidKeyException";
494+
ksNumericErrorCode = "";
495+
}
496+
} else {
497+
ksMessage = "API Level below 33, keystore exception not available";
498+
errorType = "InvalidKeyException";
499+
ksNumericErrorCode = "";
500+
}
501+
502+
return Attributes.builder()
503+
.put(AttributeName.error_type.name(), errorType)
504+
.put(AttributeName.keystore_exception_stack_trace.name(), ThrowableUtil.getStackTraceAsString(exception))
505+
.put(AttributeName.keystore_exception_message.name(), ksMessage)
506+
.put(AttributeName.keystore_numeric_error_code.name(), ksNumericErrorCode);
507+
}
508+
509+
/**
510+
* Searches the causal chain of the given throwable for an instance of
511+
* {@link android.security.KeyStoreException}.
512+
*
513+
* @param throwable The throwable to search.
514+
* @return The found KeyStoreException, or null if none was found or the API level is below 33.
515+
*/
516+
private static @Nullable android.security.KeyStoreException findKeyStoreException(@NonNull Throwable throwable) {
517+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
518+
// Check up to a max depth to avoid infinite loops in case of circular references
519+
int count = 0;
520+
while (throwable != null && count < KEYSTORE_EXCEPTION_CAUSE_CHAIN_MAX_DEPTH) {
521+
if (throwable instanceof android.security.KeyStoreException) {
522+
return (android.security.KeyStoreException) throwable;
523+
}
524+
throwable = throwable.getCause();
525+
count++;
526+
}
527+
528+
return null;
529+
} else {
530+
return null;
531+
}
532+
}
467533
}

common4j/src/main/com/microsoft/identity/common/java/opentelemetry/AttributeName.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ public enum AttributeName {
305305
*/
306306
keystore_exception_stack_trace,
307307

308+
/**
309+
* Indicates the exception message from a Android KeyStore operation exception.
310+
*/
311+
keystore_exception_message,
312+
313+
/**
314+
* Indicates the error code from a Android KeyStore operation exception.
315+
*/
316+
keystore_numeric_error_code,
317+
308318
/**
309319
* Indicates the new nonce found in the eSTS request.
310320
*/

common4j/src/main/com/microsoft/identity/common/java/platform/Device.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,25 @@ public static String getOsForDrs() {
214214
}
215215
}
216216

217+
/**
218+
* Get the Android Release OS of this device
219+
*
220+
* @return a String representing the Android Release OS information
221+
*/
222+
@NonNull
223+
@GuardedBy("sLock")
224+
public static String getAndroidReleaseOs() {
225+
sLock.readLock().lock();
226+
try {
227+
if (sDeviceMetadata != null) {
228+
return sDeviceMetadata.getAndroidReleaseOs();
229+
}
230+
return NOT_SET;
231+
} finally {
232+
sLock.readLock().unlock();
233+
}
234+
}
235+
217236
/**
218237
* Gets the manufacturer of the current device.
219238
*

common4j/src/main/com/microsoft/identity/common/java/platform/IDeviceMetadata.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ public interface IDeviceMetadata {
6666
@NonNull
6767
String getOsForMats();
6868

69+
/**
70+
* Get the Android Release OS of this device (i.e 14, 15, 16).
71+
*
72+
* @return a String representing the Release OS information
73+
*/
74+
@NonNull
75+
String getAndroidReleaseOs();
76+
6977
/**
7078
* Get the model name of this device.
7179
*

common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/MicrosoftAuthorizationRequest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ public abstract class MicrosoftAuthorizationRequest<T extends MicrosoftAuthoriza
119119
@SerializedName("x-client-OS")
120120
private final String mDiagnosticOS;
121121

122+
@Expose()
123+
@Getter
124+
@Accessors(prefix = "m")
125+
@SerializedName("x-client-ReleaseOS")
126+
private final String mDiagnosticReleaseOS;
127+
122128
@Expose()
123129
@Getter
124130
@Accessors(prefix = "m")
@@ -186,9 +192,11 @@ protected MicrosoftAuthorizationRequest(@SuppressWarnings(WarningType.rawtype_wa
186192
// If the flight is enabled, set the fields
187193
if (CommonFlightsManager.INSTANCE.getFlightsProvider().isFlightEnabled(CommonFlight.ENABLE_AM_API_WORKPROFILE_EXTRA_QUERY_PARAMETERS)) {
188194
mDiagnosticMN = Device.getManufacturer();
195+
mDiagnosticReleaseOS = Device.getAndroidReleaseOs();
189196
mWorkProfileAvailable = Device.isInPersonalProfileButClouddpcWorkProfileAvailable();
190197
} else {
191198
mDiagnosticMN = null;
199+
mDiagnosticReleaseOS = null;
192200
mWorkProfileAvailable = null;
193201
}
194202
}

0 commit comments

Comments
 (0)