Poiché il rischio e i criteri vengono valutati in tempo reale, la durata dei token delle API delle risorse può aumentare fino a 28 ore. Questi token di lunga durata vengono aggiornati in modo proattivo da Microsoft Authentication Library (MSAL), aumentando la resilienza delle applicazioni.
Per usare CAE, sia l'app che l'API delle risorse a cui accede devono essere abilitate per CAE. Se un'API della risorsa implementa CAE e l'applicazione lo dichiara in grado di gestire l'ambiente di certificazione, l'app riceve i token CAE per tale risorsa. Per questo motivo, se dichiari l'app pronta per CAE, l'applicazione deve gestire la richiesta di attestazione CAE per tutte le API di risorsa che accettano token di accesso a Microsoft Identity.
Tuttavia, la preparazione del codice per supportare le risorse abilitate per CAE non limita la possibilità di usare le API che non supportano CAE. Se l'app non gestisce correttamente le risposte CAE, potrebbe ripetere ripetutamente una chiamata API usando un token tecnicamente valido ma revocato a causa di CAE.
Per iniziare, aggiungere codice per gestire le risposte dall'API della risorsa che rifiuta la chiamata a causa di CAE. Con CAE, le API restituiscono uno stato 401 e un'intestazione WWW-Authenticate
quando il token di accesso viene revocato o l'API rileva una modifica nell'indirizzo IP usato. L'intestazione WWW-Authenticate
contiene una richiesta di attestazioni che l'applicazione può usare per acquisire un nuovo token di accesso.
Quando queste condizioni vengono soddisfatte, l'app può estrarre e decodificare la richiesta di attestazioni usando la classe MSAL.NETWwwAuthenticateParameters
.
if (APIresponse.IsSuccessStatusCode)
{
}
else
{
if (APIresponse.StatusCode == System.Net.HttpStatusCode.Unauthorized
&& APIresponse.Headers.WwwAuthenticate.Any())
{
string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(APIresponse.Headers);
L'app usa quindi la richiesta di attestazioni per acquisire un nuovo token di accesso per la risorsa.
try
{
authResult = await _clientApp.AcquireTokenSilent(scopes, firstAccount)
.WithClaims(claimChallenge)
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
try
{
authResult = await _clientApp.AcquireTokenInteractive(scopes)
.WithClaims(claimChallenge)
.WithAccount(firstAccount)
.ExecuteAsync()
.ConfigureAwait(false);
}
Quando l'applicazione è pronta per gestire la richiesta di attestazione restituita da una risorsa abilitata per CAE, è possibile indicare a Microsoft Identity che l'app è pronta per l'autenticazione condizionale. Per eseguire questa operazione nell'applicazione MSAL, compilare il client pubblico usando le funzionalità client di "cp1"
.
_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
.WithDefaultRedirectUri()
.WithAuthority(authority)
.WithClientCapabilities(new [] {"cp1"})
.Build();
Quando vengono soddisfatte queste condizioni, l'app può estrarre la richiesta di attestazioni dall'intestazione della risposta API come indicato di seguito:
try {
const response = await fetch(apiEndpoint, options);
if (response.status === 401 && response.headers.get('www-authenticate')) {
const authenticateHeader = response.headers.get('www-authenticate');
const claimsChallenge = parseChallenges(authenticateHeader).claims;
}
} catch(error) {
}
function parseChallenges(header) {
const schemeSeparator = header.indexOf(' ');
const challenges = header.substring(schemeSeparator + 1).split(',');
const challengeMap = {};
challenges.forEach((challenge) => {
const [key, value] = challenge.split('=');
challengeMap[key.trim()] = window.decodeURI(value.replace(/['"]+/g, ''));
});
return challengeMap;
}
L'app usa quindi la richiesta di attestazioni per acquisire un nuovo token di accesso per la risorsa.
const tokenRequest = {
claims: window.atob(claimsChallenge),
scopes: ['User.Read'],
account: msalInstance.getActiveAccount()
};
let tokenResponse;
try {
tokenResponse = await msalInstance.acquireTokenSilent(tokenRequest);
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
tokenResponse = await msalInstance.acquireTokenPopup(tokenRequest);
}
}
Una volta che l'applicazione è pronta per gestire la richiesta di attestazione restituita da una risorsa abilitata per CAE, è possibile indicare a Microsoft Identity che l'app è pronta per l'aggiunta di una clientCapabilities
proprietà nella configurazione MSAL.
const msalConfig = {
auth: {
clientId: 'Enter_the_Application_Id_Here',
clientCapabilities: ["CP1"]
}
}
const msalInstance = new PublicClientApplication(msalConfig);
Quando vengono soddisfatte queste condizioni, l'app può estrarre la richiesta di attestazioni dall'intestazione della risposta API come indicato di seguito:
import msal
import requests
import www_authenticate
app = msal.PublicClientApplication("your_client_id", client_capabilities=["cp1"])
...
response = requests.get("<your_resource_uri_here>")
if response.status_code == 401 and response.headers.get('WWW-Authenticate'):
parsed = www_authenticate.parse(response.headers['WWW-Authenticate'])
claims = parsed.get("bearer", {}).get("claims")
if claims:
auth_result = app.acquire_token_interactive(["scope"], claims_challenge=claims)
Dichiarare il supporto per la funzionalità client CP1
Nella configurazione dell'applicazione è necessario dichiarare che l'applicazione supporta CAE includendo la CP1
funzionalità client. Questo valore viene specificato usando la client_capabilities
proprietà JSON.
{
"client_id" : "<your_client_id>",
"authorization_user_agent" : "DEFAULT",
"redirect_uri" : "msauth://<pkg>/<cert_hash>",
"multiple_clouds_supported":true,
"broker_redirect_uri_registered": true,
"account_mode": "MULTIPLE",
"client_capabilities": "CP1",
"authorities" : [
{
"type": "AAD",
"audience": {
"type": "AzureADandPersonalMicrosoftAccount"
}
}
]
}
Rispondere alle sfide CAE in fase di esecuzione
Effettuare una richiesta a una risorsa, se la risposta contiene una richiesta di attestazioni, estrarla e rimetterla in MSAL per l'uso nella richiesta successiva.
final HttpURLConnection connection = ...;
final int responseCode = connection.getResponseCode();
if (200 == responseCode) {
} else if (401 == responseCode) {
final String authHeader = connection.getHeaderField("WWW-Authenticate");
if (null != authHeader) {
final ClaimsRequest claimsRequest = WWWAuthenticateHeader
.getClaimsRequestFromWWWAuthenticateHeaderValue(authHeader);
final AcquireTokenSilentParameters silentParameters = new AcquireTokenSilentParameters.Builder()
.fromAuthority(authority)
.forAccount(account)
.withScopes(scope)
.withClaims(claimsRequest)
.build();
try {
final IAuthenticationResult silentRequestResult = mPublicClientApplication.acquireTokenSilent(silentParameters);
} catch (final Exception e) {
if (e instanceof MsalUiRequiredException) {
}
}
}
} else {
}
I frammenti di codice seguenti descrivono il flusso di acquisizione invisibile all'utente di un token, l'esecuzione di una chiamata HTTP al provider di risorse e la gestione di un caso CAE. Potrebbe essere necessaria una chiamata di interazione aggiuntiva se la chiamata invisibile all'utente non è riuscita con attestazioni.
Dichiarare il supporto per la funzionalità client CP1
Nella configurazione dell'applicazione è necessario dichiarare che l'applicazione supporta CAE includendo la CP1
funzionalità client. Questa proprietà viene specificata utilizzando la clientCapabilities
proprietà .
let clientConfigurations = MSALPublicClientApplicationConfig(clientId: "contoso-app-ABCDE-12345",
redirectUri: "msauth.com.contoso.appbundle://auth",
authority: try MSALAuthority(url: URL(string: "https://login.microsoftonline.com/organizations")!))
clientConfigurations.clientApplicationCapabilities = ["CP1"]
let applicationContext = try MSALPublicClientApplication(configuration: clientConfigurations)
Implementare una funzione helper per l'analisi delle richieste di attestazioni.
func parsewwwAuthenticateHeader(headers:Dictionary<AnyHashable, Any>) -> String? {
guard let wwwAuthenticateHeader = headers["WWW-Authenticate"] as? String else {
return nil
}
var parameters = [String: String]()
let regex = try! NSRegularExpression(pattern: #"(\w+)="([^"]*)""#)
let matches = regex.matches(in: wwwAuthenticateHeader, range: NSRange(wwwAuthenticateHeader.startIndex..., in: wwwAuthenticateHeader))
for match in matches {
if let keyRange = Range(match.range(at: 1), in: wwwAuthenticateHeader),
let valueRange = Range(match.range(at: 2), in: wwwAuthenticateHeader) {
let key = String(wwwAuthenticateHeader[keyRange])
let value = String(wwwAuthenticateHeader[valueRange])
parameters[key] = value
}
}
guard let jsonData = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) else {
// cannot convert params into json date, end gracefully
return nil
}
return String(data: jsonData, encoding: .utf8)
}
Catch & parse 401 / richieste di attestazioni.
let response = ....
switch response.statusCode {
case 200:
break
case 401:
let headers = response.allHeaderFields
guard let wwwAuthenticateHeaderString = self.parsewwwAuthenticateHeader(headers: headers) else {
return
}
let claimsRequest = MSALClaimsRequest(jsonString: wwwAuthenticateHeaderString, error: nil)
let parameters = MSALSilentTokenParameters(scopes: "Enter_the_Protected_API_Scopes_Here", account: account)
parameters.claimsRequest = claimsRequest
applicationContext.acquireTokenSilent(with: parameters) { (result, error) in
if let error = error {
return
}
guard let result = result else {
return
}
}
break
default:
break
}
Quando vengono soddisfatte queste condizioni, l'app può estrarre la richiesta di attestazioni dall'intestazione della risposta API come indicato di seguito:
Annunciare le funzionalità client.
client, err := New("client-id", WithAuthority(authority), WithClientCapabilities([]string{"cp1"}))
analizzare l'intestazione WWW-Authenticate
e passare la richiesta di verifica risultante in MSAL-Go.
Tentare di acquisire un token in modo invisibile all'utente con la richiesta di verifica delle attestazioni.
var ar AuthResult;
ar, err := client.AcquireTokenSilent(ctx, tokenScope, public.WithClaims(claims))
È possibile testare l'applicazione accedendo a un utente e quindi usando il portale di Azure per revocare la sessione dell'utente. La volta successiva che l'app chiama l'API abilitata per CAE, all'utente verrà chiesto di ripetere l'autenticazione.