Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
vNext
----------
- [MINOR] changes accommodating the WrappedKeyAlgoIdentifier module (#2667)
- [MINOR] Using Baggage to propagate attributes from parent Span (##2671)

Version 21.2.0
----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,8 @@ public static final class AuthorizationIntentKey {
public static final String WEB_VIEW_ZOOM_CONTROLS_ENABLED = "com.microsoft.identity.web.view.zoom.controls.enabled";

public static final String WEB_VIEW_ZOOM_ENABLED = "com.microsoft.identity.web.view.zoom.enabled";

public static final String OTEL_CONTEXT_CARRIER = "otel_context_carrier";
}

public static final class AuthorizationIntentAction {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ import com.microsoft.identity.common.java.opentelemetry.AttributeName
import com.microsoft.identity.common.java.opentelemetry.OTelUtility
import com.microsoft.identity.common.java.opentelemetry.SpanName
import com.microsoft.identity.common.logging.Logger
import io.opentelemetry.api.baggage.Baggage
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.SpanContext
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.context.Context
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
import java.util.*
Expand All @@ -51,18 +52,33 @@ import java.util.*
class AuthFidoChallengeHandler (
private val fidoManager: IFidoManager,
private val webView: WebView,
private val spanContext : SpanContext?,
private val oTelContext: Context?,
private val lifecycleOwner: LifecycleOwner?
) : IChallengeHandler<FidoChallenge, Void> {
val TAG = AuthFidoChallengeHandler::class.simpleName.toString()
private val parentAttributeNames = arrayListOf(
AttributeName.correlation_id,
AttributeName.tenant_id,
AttributeName.account_type,
AttributeName.calling_package_name
)

override fun processChallenge(fidoChallenge: FidoChallenge): Void? {
val methodTag = "$TAG:processChallenge"
Logger.info(methodTag, "Processing FIDO challenge.")
val span = if (spanContext != null) {
OTelUtility.createSpanFromParent(SpanName.Fido.name, spanContext)
val span : Span
if (oTelContext != null) {
val parentSpan = Span.fromContext(oTelContext)
val spanContext = parentSpan.spanContext
span = OTelUtility.createSpanFromParent(SpanName.Fido.name, spanContext)
val baggage = Baggage.fromContext(oTelContext)
parentAttributeNames.forEach { attributeName ->
baggage.getEntryValue(attributeName.name)?.let { value ->
span.setAttribute(attributeName.name, value)
}
}
} else {
OTelUtility.createSpan(SpanName.Fido.name)
span = OTelUtility.createSpan(SpanName.Fido.name)
}
span.setAttribute(
AttributeName.fido_challenge_handler.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
// THE SOFTWARE.
package com.microsoft.identity.common.internal.providers.oauth2;

import static com.microsoft.identity.common.adal.internal.AuthenticationConstants.AuthorizationIntentKey.OTEL_CONTEXT_CARRIER;

import android.os.Bundle;

import androidx.annotation.Nullable;
Expand All @@ -31,9 +33,14 @@
import com.microsoft.identity.common.internal.util.CommonMoshiJsonAdapter;
import com.microsoft.identity.common.java.exception.TerminalException;
import com.microsoft.identity.common.java.opentelemetry.SerializableSpanContext;
import com.microsoft.identity.common.java.opentelemetry.TextMapPropagatorExtension;
import com.microsoft.identity.common.logging.Logger;

import java.util.HashMap;
import java.util.Map;

import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Context;
import lombok.Getter;
import lombok.experimental.Accessors;

Expand All @@ -43,6 +50,11 @@ public class AuthorizationActivity extends DualScreenActivity {
@Getter
@Accessors(prefix = "m")
private SpanContext mSpanContext;

@Getter
@Accessors(prefix = "m")
private Context mOtelContext;

private AuthorizationFragment mFragment;

public AuthorizationFragment getFragment() {
Expand All @@ -60,6 +72,21 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
getIntent().getExtras().getString(SerializableSpanContext.SERIALIZABLE_SPAN_CONTEXT),
SerializableSpanContext.class
);
// Extract OtelContext from the carrier if it exists
final Map<String, String> carrier;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
carrier = getIntent().getExtras() != null ?
getIntent().getExtras().getSerializable(OTEL_CONTEXT_CARRIER, HashMap.class) :
new HashMap<>();
} else {
@SuppressWarnings("unchecked")
Map<String, String> temp = getIntent().getExtras() != null ?
(Map<String, String>) getIntent().getExtras().getSerializable(OTEL_CONTEXT_CARRIER) :
new HashMap<>();
carrier = temp;
}
mOtelContext = TextMapPropagatorExtension.extract(carrier);

} catch (final TerminalException e) {
// Don't want to block any features if an error occurs during deserialization of the span context.
mSpanContext = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.microsoft.identity.common.adal.internal.AuthenticationConstants
import com.microsoft.identity.common.adal.internal.AuthenticationConstants.AuthorizationIntentKey.OTEL_CONTEXT_CARRIER
import com.microsoft.identity.common.internal.msafederation.getIdProviderExtraQueryParamForAuthorization
import com.microsoft.identity.common.internal.msafederation.getIdProviderHeadersForAuthorization
import com.microsoft.identity.common.internal.msafederation.google.SignInWithGoogleApi.Companion.getInstance
Expand All @@ -40,8 +41,10 @@ import com.microsoft.identity.common.java.exception.ClientException
import com.microsoft.identity.common.java.logging.DiagnosticContext
import com.microsoft.identity.common.java.opentelemetry.SerializableSpanContext
import com.microsoft.identity.common.java.opentelemetry.SpanExtension
import com.microsoft.identity.common.java.opentelemetry.TextMapPropagatorExtension
import com.microsoft.identity.common.java.ui.AuthorizationAgent
import com.microsoft.identity.common.java.util.CommonURIBuilder
import io.opentelemetry.context.Context
import java.net.URISyntaxException


Expand Down Expand Up @@ -118,6 +121,10 @@ object AuthorizationActivityFactory {
.build()
)
)
putExtra(
OTEL_CONTEXT_CARRIER,
TextMapPropagatorExtension.inject(Context.current())
)
if (parameters.sourceLibraryName != null) {
putExtra(PRODUCT, parameters.sourceLibraryName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;

/**
Expand Down Expand Up @@ -258,7 +259,7 @@ private boolean handleUrl(final WebView view, final String url) {
Logger.info(methodTag,"WebView detected request for passkey protocol.");
final FidoChallenge challenge = FidoChallenge.createFromRedirectUri(url);
final Activity currentActivity = getActivity();
final SpanContext spanContext = currentActivity instanceof AuthorizationActivity ? ((AuthorizationActivity)currentActivity).getSpanContext() : null;
final Context oTelContext = currentActivity instanceof AuthorizationActivity ? ((AuthorizationActivity)currentActivity).getOtelContext() : null;
// The legacyManager should only be getting added if the device is on Android 13 or lower and the library is MSAL/OneAuth with fragment or dialog mode.
// The legacyManager logic should be removed once a larger majority of users are on Android 14+.
final IFidoManager legacyManager =
Expand All @@ -274,7 +275,7 @@ private boolean handleUrl(final WebView view, final String url) {
legacyManager
),
view,
spanContext,
oTelContext,
ViewTreeLifecycleOwner.get(view));
challengeHandler.processChallenge(challenge);
} else if (CommonFlightsManager.INSTANCE.getFlightsProvider().isFlightEnabled(CommonFlight.ENABLE_ATTACH_NEW_PRT_HEADER_WHEN_NONCE_EXPIRED) && isNonceRedirect(formattedURL)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class AuthFidoChallengeHandlerTest {
authFidoChallengeHandler = AuthFidoChallengeHandler(
fidoManager = testFidoManager,
webView = webView,
spanContext = null,
oTelContext = null,
lifecycleOwner = testLifecycleOwner
)
}
Expand Down Expand Up @@ -126,7 +126,7 @@ class AuthFidoChallengeHandlerTest {
authFidoChallengeHandler = AuthFidoChallengeHandler(
fidoManager = testFidoManager,
webView = webView,
spanContext = null,
oTelContext = null,
lifecycleOwner = null
)
assertFalse(webView.urlLoaded)
Expand Down
1 change: 1 addition & 0 deletions common4j/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ dependencies {
resolvableTestFixturesImplementation "org.robolectric:junit:$rootProject.ext.robolectricVersion"

implementation("io.opentelemetry:opentelemetry-api:$rootProject.ext.openTelemetryVersion")
implementation "io.opentelemetry:opentelemetry-sdk:$rootProject.ext.openTelemetryVersion"
}

sourceCompatibility = "1.8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,5 +363,28 @@ public enum AttributeName {
/**
* Records the if the broker handled a switch browser resume,
*/
is_switch_browser_resume_handled
is_switch_browser_resume_handled,

/**
* The tenant id for the home tenant of the account for which PRT is required.
*/
tenant_id,

/**
* Indicates the type of account such as AAD or MSA.
*/
account_type,

/**
* Indicates the broker app that emits the event.
* The broker is not necessarily the active broker.
* e.g. An inactive broker app might be invoked during OnUpgrade.
* (It should be renamed, but that would mess up the dashboard)
*/
active_broker_package_name,

/**
* Indicates the current broker package name processing the request.
*/
current_broker_package_name
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.opentelemetry;

import com.microsoft.identity.common.java.logging.Logger;

import java.util.List;

import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.baggage.BaggageBuilder;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.sdk.trace.ReadableSpan;

/**
* Utility class for working with OpenTelemetry Baggage objects.
*/
public class BaggageExtension {

private static final String TAG = BaggageExtension.class.getSimpleName();

/**
* Default constructor.
*/
private BaggageExtension() {
// Utility class, private constructor to prevent instantiation
}

/**
* Extracts baggage items from a ReadableSpan based on the specified attribute names.
*
* @param span The span from which to extract baggage data.
* @param attributeNames List of attribute names to extract from the span.
* @return A Baggage object containing extracted attributes.
*/
public static Baggage getBaggageFromReadableSpan(final Span span, final List<String> attributeNames) {
final BaggageBuilder baggageBuilder = Baggage.builder();
if (span instanceof ReadableSpan && attributeNames != null && !attributeNames.isEmpty()) {
ReadableSpan readableSpan = (ReadableSpan) span;
attributeNames.forEach(attributeName -> {
final String value = readableSpan.getAttribute(AttributeKey.stringKey(attributeName));

if (value != null && !value.isEmpty()) {
baggageBuilder.put(attributeName, value);
}
});
}

return baggageBuilder.build();
}

/**
* Makes the provided Baggage current in the context, catching any exceptions silently.
* This is useful in scenarios where Baggage propagation should not interrupt normal operation flow.
*
* @param baggage The Baggage to make current.
* @return the resulting scope.
*/
public static Scope makeBaggageCurrent(final Baggage baggage) {
if (baggage == null) {
return SpanExtension.NoopScope.INSTANCE;
}

try {
return baggage.storeInContext(Context.current()).makeCurrent();
} catch (Exception e) {
Logger.error(TAG + ":makeBaggageCurrent", e.getMessage(), e);
return SpanExtension.NoopScope.INSTANCE;
}
}
}
Loading
Loading