internal static void SetBrokerResult(Intent data, int resultCode)
        {
            if (resultCode != BrokerResponseCode.ResponseReceived)
            {
                resultEx = new AuthenticationResultEx
                {
                    Exception =
                        new AdalException(data.GetStringExtra(BrokerConstants.ResponseErrorCode),
                                          data.GetStringExtra(BrokerConstants.ResponseErrorMessage))
                };
            }
            else
            {
                var tokenResponse = new TokenResponse
                {
                    // Authority = data.GetStringExtra(BrokerConstants.AccountAuthority),
                    AccessToken   = data.GetStringExtra(BrokerConstants.AccountAccessToken),
                    IdTokenString = data.GetStringExtra(BrokerConstants.AccountIdToken),
                    TokenType     = "Bearer",
                    ExpiresOn     = data.GetLongExtra(BrokerConstants.AccountExpireDate, 0)
                };

                resultEx = tokenResponse.GetResult(BrokerProxy.ConvertFromTimeT(tokenResponse.ExpiresOn),
                                                   BrokerProxy.ConvertFromTimeT(tokenResponse.ExpiresOn));
            }

            readyForResponse.Release();
        }
        protected override async Task <AuthenticationResultEx> SendTokenRequestAsync()
        {
            TimeSpan timeRemaining          = deviceCodeResult.ExpiresOn - DateTimeOffset.UtcNow;
            AuthenticationResultEx resultEx = null;

            while (timeRemaining.TotalSeconds > 0)
            {
                try
                {
                    resultEx = await base.SendTokenRequestAsync().ConfigureAwait(false);

                    break;
                }
                catch (AdalServiceException exc)
                {
                    if (!exc.ErrorCode.Equals(AdalErrorEx.DeviceCodeAuthorizationPendingError))
                    {
                        throw;
                    }
                }

                await Task.Delay(TimeSpan.FromSeconds(deviceCodeResult.Interval)).ConfigureAwait(false);

                timeRemaining = deviceCodeResult.ExpiresOn - DateTimeOffset.UtcNow;
            }

            return(resultEx);
        }
        internal static void SetBrokerResult(Intent data, int resultCode)
        {
            if (resultCode != BrokerResponseCode.ResponseReceived)
            {
                resultEx = new AuthenticationResultEx
                {
                    Exception =
                        new AdalException(data.GetStringExtra(BrokerConstants.ResponseErrorCode),
                                          data.GetStringExtra(BrokerConstants.ResponseErrorMessage))
                };
            }
            else
            {
                string         accessToken = data.GetStringExtra(BrokerConstants.AccountAccessToken);
                DateTimeOffset expiresOn   = BrokerProxy.ConvertFromTimeT(data.GetLongExtra(BrokerConstants.AccountExpireDate, 0));
                UserInfo       userInfo    = BrokerProxy.GetUserInfoFromBrokerResult(data.Extras);
                resultEx = new AuthenticationResultEx
                {
                    Result = new AuthenticationResult("Bearer", accessToken, expiresOn)
                    {
                        UserInfo = userInfo
                    }
                };
            }

            readyForResponse.Release();
        }
コード例 #4
0
        internal void StoreToCache(AuthenticationResultEx result, string authority, string resource, string clientId, TokenSubjectType subjectType, CallState callState)
        {
            lock (cacheLock)
            {
                PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache...");

                string uniqueId      = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null;
                string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null;

                this.OnBeforeWrite(new TokenCacheNotificationArgs
                {
                    Resource      = resource,
                    ClientId      = clientId,
                    UniqueId      = uniqueId,
                    DisplayableId = displayableId
                });

                TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType,
                                                                result.Result.UserInfo);
                this.tokenCacheDictionary[tokenCacheKey] = result;
                PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache");
                this.UpdateCachedMrrtRefreshTokens(result, clientId, subjectType);

                this.HasStateChanged = true;
            }
        }
        internal async Task StoreToCacheAsync(AuthenticationResultEx result, string authority, string resource, string clientId,
                                              TokenSubjectType subjectType, CallState callState)
        {
            var metadata = await InstanceDiscovery.GetMetadataEntryAsync(new Uri(authority), false, callState).ConfigureAwait(false);

            StoreToCacheCommon(result, ReplaceHost(authority, metadata.PreferredCache), resource, clientId, subjectType, callState);
        }
コード例 #6
0
        protected override async Task <AuthenticationResultEx> SendTokenRequestAsync()
        {
            AuthenticationResultEx resultEx = await base.SendTokenRequestAsync().ConfigureAwait(false);

            if (resultEx != null)
            {
                resultEx.UserAssertionHash = CacheQueryData.AssertionHash;
            }

            return(resultEx);
        }
コード例 #7
0
        /// <summary>
        /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize.
        /// </summary>
        /// <param name="state">State of the cache as a blob</param>
        public void Deserialize(byte[] state)
        {
            lock (cacheLock)
            {
                if (state == null)
                {
                    this.tokenCacheDictionary.Clear();
                    return;
                }

                using (Stream stream = new MemoryStream())
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(state);
                    writer.Flush();
                    stream.Position = 0;

                    BinaryReader reader        = new BinaryReader(stream);
                    int          schemaVersion = reader.ReadInt32();
                    if (schemaVersion != SchemaVersion)
                    {
                        CallState.Default.Logger.Warning(null,
                                                         "The version of the persistent state of the cache does not match the current schema, so skipping deserialization.");
                        return;
                    }

                    this.tokenCacheDictionary.Clear();
                    int count = reader.ReadInt32();
                    for (int n = 0; n < count; n++)
                    {
                        string keyString = reader.ReadString();

                        string[] kvpElements            = keyString.Split(new[] { Delimiter }, StringSplitOptions.None);
                        AuthenticationResultEx resultEx = AuthenticationResultEx.Deserialize(reader.ReadString());
                        TokenCacheKey          key      = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2],
                                                                            (TokenSubjectType)int.Parse(kvpElements[3], CultureInfo.CurrentCulture),
                                                                            resultEx.Result.UserInfo);

                        this.tokenCacheDictionary.Add(key, resultEx);
                    }

                    CallState.Default.Logger.Information(null,
                                                         string.Format(CultureInfo.CurrentCulture, "Deserialized {0} items to token cache.", count));
                }
            }
        }
        public async Task <AuthenticationResultEx> AcquireTokenUsingBroker(IDictionary <string, string> brokerPayload)
        {
            resultEx         = null;
            readyForResponse = new SemaphoreSlim(0);
            try
            {
                await Task.Run(() => AcquireToken(brokerPayload)).ConfigureAwait(false);
            }
            catch (Exception exc)
            {
                PlatformPlugin.Logger.Error(null, exc);
                throw;
            }
            await readyForResponse.WaitAsync().ConfigureAwait(false);

            return(resultEx);
        }
        protected override void PostTokenRequest(AuthenticationResultEx resultEx)
        {
            base.PostTokenRequest(resultEx);
            UserInfo userInfo = resultEx.Result.UserInfo;
            this.UniqueId = (userInfo == null) ? null : userInfo.UniqueId;
            this.DisplayableId = (userInfo == null) ? null : userInfo.DisplayableId;
            if (resultEx.ResourceInResponse != null)
            {
                this.Resource = resultEx.ResourceInResponse;
                PlatformPlugin.Logger.Verbose(this.CallState, "Resource value in the token response was used for storing tokens in the cache");
            }

            // If resource is not passed as an argument and is not returned by STS either, 
            // we cannot store the token in the cache with null resource.
            // TODO: Store refresh token though if STS supports MRRT.
            this.StoreToCache = this.StoreToCache && (this.Resource != null);
        }
        internal async Task <AuthenticationResultEx> LoadFromCacheAsync(CacheQueryData cacheQueryData, CallState callState)
        {
            AuthenticationResultEx resultEx = null;
            var aliasedHosts = await GetOrderedAliasesAsync(cacheQueryData.Authority, false, callState).ConfigureAwait(false);

            foreach (var aliasedHost in aliasedHosts)
            {
                cacheQueryData.Authority = ReplaceHost(cacheQueryData.Authority, aliasedHost);
                resultEx = LoadFromCacheCommon(cacheQueryData, callState);
                if (resultEx?.Result != null)
                {
                    break;
                }
            }

            return(resultEx);
        }
コード例 #11
0
        protected async Task <AuthenticationResultEx> SendTokenRequestByRefreshTokenAsync(string refreshToken)
        {
            var requestParameters = new DictionaryRequestParameters(this.Resource, this.ClientKey);

            requestParameters[OAuthParameter.GrantType]    = OAuthGrantType.RefreshToken;
            requestParameters[OAuthParameter.RefreshToken] = refreshToken;
            requestParameters[OAuthParameter.Scope]        = OAuthValue.ScopeOpenId;

            AuthenticationResultEx result = await this.SendHttpMessageAsync(requestParameters);

            if (result.RefreshToken == null)
            {
                result.RefreshToken = refreshToken;
                PlatformPlugin.Logger.Verbose(this.CallState, "Refresh token was missing from the token refresh response, so the refresh token in the request is returned instead");
            }

            return(result);
        }
コード例 #12
0
        protected override void PostTokenRequest(AuthenticationResultEx resultEx)
        {
            base.PostTokenRequest(resultEx);
            UserInfo userInfo = resultEx.Result.UserInfo;

            this.UniqueId      = (userInfo == null) ? null : userInfo.UniqueId;
            this.DisplayableId = (userInfo == null) ? null : userInfo.DisplayableId;
            if (resultEx.ResourceInResponse != null)
            {
                this.Resource = resultEx.ResourceInResponse;
                PlatformPlugin.Logger.Verbose(this.CallState, "Resource value in the token response was used for storing tokens in the cache");
            }

            // If resource is not passed as an argument and is not returned by STS either,
            // we cannot store the token in the cache with null resource.
            // TODO: Store refresh token though if STS supports MRRT.
            this.StoreToCache = this.StoreToCache && (this.Resource != null);
        }
コード例 #13
0
        private async Task <AuthenticationResultEx> RefreshAccessTokenAsync(AuthenticationResultEx result)
        {
            AuthenticationResultEx newResultEx = null;

            if (this.Resource != null)
            {
                CallState.Logger.Verbose(this.CallState, "Refreshing access token...");

                try
                {
                    newResultEx = await this.SendTokenRequestByRefreshTokenAsync(result.RefreshToken)
                                  .ConfigureAwait(false);

                    this.Authenticator.UpdateTenantId(result.Result.TenantId);

                    newResultEx.Result.Authority = Authenticator.Authority;

                    if (newResultEx.Result.IdToken == null)
                    {
                        // If Id token is not returned by token endpoint when refresh token is redeemed, we should copy tenant and user information from the cached token.
                        newResultEx.Result.UpdateTenantAndUserInfo(result.Result.TenantId, result.Result.IdToken,
                                                                   result.Result.UserInfo);
                    }
                }
                catch (AdalException ex)
                {
                    AdalServiceException serviceException = ex as AdalServiceException;
                    if (serviceException != null && serviceException.ErrorCode == "invalid_request")
                    {
                        throw new AdalServiceException(
                                  AdalError.FailedToRefreshToken,
                                  AdalErrorMessage.FailedToRefreshToken + ". " + serviceException.Message,
                                  serviceException.ServiceErrorCodes,
                                  serviceException);
                    }
                    newResultEx = new AuthenticationResultEx {
                        Exception = ex
                    };
                }
            }

            return(newResultEx);
        }
        protected override void PostTokenRequest(AuthenticationResultEx resultEx)
        {
            base.PostTokenRequest(resultEx);
            UserInfo userInfo = resultEx.Result.UserInfo;
            this.UniqueId = (userInfo == null) ? null : userInfo.UniqueId;
            this.DisplayableId = (userInfo == null) ? null : userInfo.DisplayableId;
            if (!ADALScopeHelper.IsNullOrEmpty(resultEx.ScopeInResponse))
            {
                // This sets the Handler's Scope to the most recent loop, the id_token, or scope=openid.
                // ADAL then tries to return an AuthResult with this scope from the cache.
                // What's more, ADAL tries to load scope "openid" from the cache and misses b/c the scope was cached as the clientId.
                //this.Scope = resultEx.ScopeInResponse;
                //PlatformPlugin.Logger.Verbose(this.CallState, "Resource value in the token response was used for storing tokens in the cache");
            }

            // If resource is not passed as an argument and is not returned by STS either, 
            // we cannot store the token in the cache with null resource.
            // TODO: Store refresh token though if STS supports MRRT.
            this.StoreToCache = this.StoreToCache && (!ADALScopeHelper.IsNullOrEmpty(this.Scope));
        }
コード例 #15
0
        private void UpdateCachedMrrtRefreshTokens(AuthenticationResultEx result, string clientId, TokenSubjectType subjectType)
        {
            lock (cacheLock)
            {
                if (result.Result.UserInfo != null && result.IsMultipleResourceRefreshToken)
                {
                    //pass null for authority to update the token for all the tenants
                    List <KeyValuePair <TokenCacheKey, AuthenticationResultEx> > mrrtItems =
                        this.QueryCache(null, clientId, subjectType, result.Result.UserInfo.UniqueId,
                                        result.Result.UserInfo.DisplayableId, null)
                        .Where(p => p.Value.IsMultipleResourceRefreshToken)
                        .ToList();

                    foreach (KeyValuePair <TokenCacheKey, AuthenticationResultEx> mrrtItem in mrrtItems)
                    {
                        mrrtItem.Value.RefreshToken = result.RefreshToken;
                    }
                }
            }
        }
        protected async Task <AuthenticationResultEx> SendTokenRequestByRefreshTokenAsync(string refreshToken)
        {
            var requestParameters = new DictionaryRequestParameters(this.Resource, this.ClientKey);

            requestParameters[OAuthParameter.GrantType]    = OAuthGrantType.RefreshToken;
            requestParameters[OAuthParameter.RefreshToken] = refreshToken;

            // Commented due to a problem with AD not allowing scopes. Please, see http://stackoverflow.com/questions/42208919/refresh-tokens-with-adfs-3-0-adal-web-api-and-xamarin
            //requestParameters[OAuthParameter.Scope] = OAuthValue.ScopeOpenId;

            AuthenticationResultEx result = await this.SendHttpMessageAsync(requestParameters).ConfigureAwait(false);

            if (result.RefreshToken == null)
            {
                result.RefreshToken = refreshToken;
                PlatformPlugin.Logger.Verbose(this.CallState,
                                              "Refresh token was missing from the token refresh response, so the refresh token in the request is returned instead");
            }

            return(result);
        }
        protected override void PostTokenRequest(AuthenticationResultEx resultEx)
        {
            base.PostTokenRequest(resultEx);
            if ((this.DisplayableId == null && this.UniqueId == null) || this.UserIdentifierType == UserIdentifierType.OptionalDisplayableId)
            {
                return;
            }

            string uniqueId      = (resultEx.Result.UserInfo != null && resultEx.Result.UserInfo.UniqueId != null) ? resultEx.Result.UserInfo.UniqueId : "NULL";
            string displayableId = (resultEx.Result.UserInfo != null) ? resultEx.Result.UserInfo.DisplayableId : "NULL";

            if (this.UserIdentifierType == UserIdentifierType.UniqueId && string.Compare(uniqueId, this.UniqueId, StringComparison.Ordinal) != 0)
            {
                throw new AdalUserMismatchException(this.UniqueId, uniqueId);
            }

            if (this.UserIdentifierType == UserIdentifierType.RequiredDisplayableId && string.Compare(displayableId, this.DisplayableId, StringComparison.OrdinalIgnoreCase) != 0)
            {
                throw new AdalUserMismatchException(this.DisplayableId, displayableId);
            }
        }
        public AuthenticationResultEx GetResult(DateTimeOffset expiresOn, DateTimeOffset extendedExpiresOn)
        {
            AuthenticationResultEx resultEx;

            if (this.AccessToken != null)
            {
                var result = new AuthenticationResult(this.TokenType, this.AccessToken, expiresOn, extendedExpiresOn);

                IdToken idToken = IdToken.Parse(this.IdTokenString);
                if (idToken != null)
                {
                    string tenantId      = idToken.TenantId;
                    string uniqueId      = null;
                    string displayableId = null;

                    if (!string.IsNullOrWhiteSpace(idToken.ObjectId))
                    {
                        uniqueId = idToken.ObjectId;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Subject))
                    {
                        uniqueId = idToken.Subject;
                    }

                    if (!string.IsNullOrWhiteSpace(idToken.UPN))
                    {
                        displayableId = idToken.UPN;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Email))
                    {
                        displayableId = idToken.Email;
                    }

                    string         givenName             = idToken.GivenName;
                    string         familyName            = idToken.FamilyName;
                    string         identityProvider      = idToken.IdentityProvider ?? idToken.Issuer;
                    DateTimeOffset?passwordExpiresOffest = null;
                    if (idToken.PasswordExpiration > 0)
                    {
                        passwordExpiresOffest = DateTime.UtcNow + TimeSpan.FromSeconds(idToken.PasswordExpiration);
                    }

                    Uri changePasswordUri = null;
                    if (!string.IsNullOrEmpty(idToken.PasswordChangeUrl))
                    {
                        changePasswordUri = new Uri(idToken.PasswordChangeUrl);
                    }

                    result.UpdateTenantAndUserInfo(tenantId, this.IdTokenString,
                                                   new UserInfo
                    {
                        UniqueId          = uniqueId,
                        DisplayableId     = displayableId,
                        GivenName         = givenName,
                        FamilyName        = familyName,
                        IdentityProvider  = identityProvider,
                        PasswordExpiresOn = passwordExpiresOffest,
                        PasswordChangeUrl = changePasswordUri
                    });

                    result.Authority = Authority;
                }

                resultEx = new AuthenticationResultEx
                {
                    Result       = result,
                    RefreshToken = this.RefreshToken,
                    // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need
                    // to get it from the STS response.
                    ResourceInResponse = this.Resource
                };
            }
            else if (this.Error != null)
            {
                throw new AdalServiceException(this.Error, this.ErrorDescription);
            }
            else
            {
                throw new AdalServiceException(AdalError.Unknown, AdalErrorMessage.Unknown);
            }

            return(resultEx);
        }
コード例 #19
0
        public void AcquireToken(IDictionary <string, string> brokerPayload)
        {
            if (brokerPayload.ContainsKey("broker_install_url"))
            {
                string url   = brokerPayload["broker_install_url"];
                Uri    uri   = new Uri(url);
                string query = uri.Query;
                if (query.StartsWith("?"))
                {
                    query = query.Substring(1);
                }

                Dictionary <string, string> keyPair = EncodingHelper.ParseKeyValueList(query, '&', true, false, null);

                PlatformParameters pp = PlatformParameters as PlatformParameters;
                pp.CallerActivity.StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse(keyPair["app_link"])));

                throw new AdalException(AdalErrorAndroidEx.BrokerApplicationRequired, AdalErrorMessageAndroidEx.BrokerApplicationRequired);
            }

            Context mContext = Application.Context;
            AuthenticationRequest request        = new AuthenticationRequest(brokerPayload);
            PlatformParameters    platformParams = PlatformParameters as PlatformParameters;

            // BROKER flow intercepts here
            // cache and refresh call happens through the authenticator service
            if (mBrokerProxy.VerifyUser(request.LoginHint,
                                        request.UserId))
            {
                CallState.Logger.Verbose(null, "It switched to broker for context: " + mContext.PackageName);
                request.BrokerAccountName = request.LoginHint;

                // Don't send background request, if prompt flag is always or
                // refresh_session
                bool hasAccountNameOrUserId = !string.IsNullOrEmpty(request.BrokerAccountName) || !string.IsNullOrEmpty(request.UserId);
                if (string.IsNullOrEmpty(request.Claims) && hasAccountNameOrUserId)
                {
                    CallState.Logger.Verbose(null, "User is specified for background token request");
                    resultEx = mBrokerProxy.GetAuthTokenInBackground(request, platformParams.CallerActivity);
                }
                else
                {
                    CallState.Logger.Verbose(null, "User is not specified for background token request");
                }

                if (resultEx != null && resultEx.Result != null && !string.IsNullOrEmpty(resultEx.Result.AccessToken))
                {
                    CallState.Logger.Verbose(null, "Token is returned from background call ");
                    readyForResponse.Release();
                    return;
                }

                // Launch broker activity
                // if cache and refresh request is not handled.
                // Initial request to authenticator needs to launch activity to
                // record calling uid for the account. This happens for Prompt auto
                // or always behavior.
                CallState.Logger.Verbose(null, "Token is not returned from backgroud call");

                // Only happens with callback since silent call does not show UI
                CallState.Logger.Verbose(null, "Launch activity for Authenticator");
                CallState.Logger.Verbose(null, "Starting Authentication Activity");
                if (resultEx == null)
                {
                    CallState.Logger.Verbose(null, "Initial request to authenticator");
                    // Log the initial request but not force a prompt
                }

                if (brokerPayload.ContainsKey("silent_broker_flow"))
                {
                    throw new AdalSilentTokenAcquisitionException();
                }

                // onActivityResult will receive the response
                // Activity needs to launch to record calling app for this
                // account
                Intent brokerIntent = mBrokerProxy.GetIntentForBrokerActivity(request, platformParams.CallerActivity);
                if (brokerIntent != null)
                {
                    try
                    {
                        CallState.Logger.Verbose(null, "Calling activity pid:" + Android.OS.Process.MyPid()
                                                 + " tid:" + Android.OS.Process.MyTid() + "uid:"
                                                 + Android.OS.Process.MyUid());
                        platformParams.CallerActivity.StartActivityForResult(brokerIntent, 1001);
                    }
                    catch (ActivityNotFoundException e)
                    {
                        CallState.Logger.Error(null, e);
                    }
                }
            }
            else
            {
                throw new AdalException(AdalErrorAndroidEx.NoBrokerAccountFound, "Add requested account as a Workplace account via Settings->Accounts or set UseBroker=true.");
            }
        }
コード例 #20
0
        public AuthenticationResultEx GetResult()
        {
            AuthenticationResultEx resultEx;

            if (this.AccessToken != null)
            {
                DateTimeOffset expiresOn = DateTime.UtcNow + TimeSpan.FromSeconds(this.ExpiresIn);

                var result = new AuthenticationResult(this.TokenType, this.AccessToken, expiresOn);

                IdToken idToken = IdToken.Parse(this.IdTokenString);
                if (idToken != null)
                {
                    string tenantId = idToken.TenantId;
                    string uniqueId = null;
                    string displayableId = null;

                    if (!string.IsNullOrWhiteSpace(idToken.ObjectId))
                    {
                        uniqueId = idToken.ObjectId;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Subject))
                    {
                        uniqueId = idToken.Subject;
                    }

                    if (!string.IsNullOrWhiteSpace(idToken.UPN))
                    {
                        displayableId = idToken.UPN;
                    }
                    else if (!string.IsNullOrWhiteSpace(idToken.Email))
                    {
                        displayableId = idToken.Email;
                    }

                    string givenName = idToken.GivenName;
                    string familyName = idToken.FamilyName;
                    string identityProvider = idToken.IdentityProvider ?? idToken.Issuer;
                    DateTimeOffset? passwordExpiresOffest = null;
                    if (idToken.PasswordExpiration > 0)
                    {
                        passwordExpiresOffest = DateTime.UtcNow + TimeSpan.FromSeconds(idToken.PasswordExpiration);
                    }

                    Uri changePasswordUri = null;
                    if (!string.IsNullOrEmpty(idToken.PasswordChangeUrl))
                    {
                        changePasswordUri = new Uri(idToken.PasswordChangeUrl);
                    }

                    result.UpdateTenantAndUserInfo(tenantId, this.IdTokenString, new UserInfo { UniqueId = uniqueId, DisplayableId = displayableId, GivenName = givenName, FamilyName = familyName, IdentityProvider = identityProvider, PasswordExpiresOn = passwordExpiresOffest, PasswordChangeUrl = changePasswordUri });
                }

                resultEx = new AuthenticationResultEx
                {
                    Result = result,
                    RefreshToken = this.RefreshToken,
                    // This is only needed for AcquireTokenByAuthorizationCode in which parameter resource is optional and we need
                    // to get it from the STS response.
                    ResourceInResponse = this.Resource                    
                };
            }
            else if (this.Error != null)
            {
                throw new AdalServiceException(this.Error, this.ErrorDescription);
            }
            else
            {
                throw new AdalServiceException(AdalError.Unknown, AdalErrorMessage.Unknown);
            }

            return resultEx;
        }
コード例 #21
0
        private async Task<AuthenticationResultEx> RefreshAccessTokenAsync(AuthenticationResultEx result)
        {
            AuthenticationResultEx newResultEx = null;

            if (this.Resource != null)
            {
                PlatformPlugin.Logger.Verbose(this.CallState, "Refreshing access token...");

                try
                {
                    newResultEx = await this.SendTokenRequestByRefreshTokenAsync(result.RefreshToken);
                    this.Authenticator.UpdateTenantId(result.Result.TenantId);

                    if (newResultEx.Result.IdToken == null)
                    {
                        // If Id token is not returned by token endpoint when refresh token is redeemed, we should copy tenant and user information from the cached token.
                        newResultEx.Result.UpdateTenantAndUserInfo(result.Result.TenantId, result.Result.IdToken, result.Result.UserInfo);
                    }
                }
                catch (AdalException ex)
                {
                    AdalServiceException serviceException = ex as AdalServiceException;
                    if (serviceException != null && serviceException.ErrorCode == "invalid_request")
                    {
                        throw new AdalServiceException(
                            AdalError.FailedToRefreshToken,
                            AdalErrorMessage.FailedToRefreshToken + ". " + serviceException.Message,
                            serviceException.ServiceErrorCodes,
                            serviceException.InnerException);
                    }

                    newResultEx = null;
                }
            }

            return newResultEx;
        }
コード例 #22
0
        public async Task <AuthenticationResult> RunAsync()
        {
            bool notifiedBeforeAccessCache = false;
            AuthenticationResultEx extendedLifetimeResultEx = null;

            try
            {
                await this.PreRunAsync().ConfigureAwait(false);

                if (this.LoadFromCache)
                {
                    CallState.Logger.Verbose(CallState, "Loading from cache.");
                    CacheQueryData.Authority     = Authenticator.Authority;
                    CacheQueryData.Resource      = this.Resource;
                    CacheQueryData.ClientId      = this.ClientKey.ClientId;
                    CacheQueryData.SubjectType   = this.TokenSubjectType;
                    CacheQueryData.UniqueId      = this.UniqueId;
                    CacheQueryData.DisplayableId = this.DisplayableId;

                    this.NotifyBeforeAccessCache();
                    notifiedBeforeAccessCache = true;
                    ResultEx = this.tokenCache.LoadFromCache(CacheQueryData, this.CallState);
                    extendedLifetimeResultEx = ResultEx;

                    if (ResultEx?.Result != null &&
                        ((ResultEx.Result.AccessToken == null && ResultEx.RefreshToken != null) ||
                         (ResultEx.Result.ExtendedLifeTimeToken && ResultEx.RefreshToken != null)))
                    {
                        ResultEx = await this.RefreshAccessTokenAsync(ResultEx).ConfigureAwait(false);

                        if (ResultEx != null && ResultEx.Exception == null)
                        {
                            StoreResultExToCache(ref notifiedBeforeAccessCache);
                        }
                    }
                }

                if (ResultEx == null || ResultEx.Exception != null)
                {
                    if (brokerHelper.CanInvokeBroker)
                    {
                        ResultEx = await brokerHelper.AcquireTokenUsingBroker(brokerParameters).ConfigureAwait(false);
                    }
                    else
                    {
                        await this.PreTokenRequest().ConfigureAwait(false);

                        // check if broker app installation is required for authentication.
                        await CheckAndAcquireTokenUsingBroker().ConfigureAwait(false);
                    }

                    //broker token acquisition failed
                    if (ResultEx != null && ResultEx.Exception != null)
                    {
                        throw ResultEx.Exception;
                    }

                    this.PostTokenRequest(ResultEx);
                    StoreResultExToCache(ref notifiedBeforeAccessCache);
                }

                await this.PostRunAsync(ResultEx.Result).ConfigureAwait(false);

                return(ResultEx.Result);
            }
            catch (Exception ex)
            {
                CallState.Logger.Error(this.CallState, ex);
                if (client != null && client.Resiliency && extendedLifetimeResultEx != null)
                {
                    CallState.Logger.Information(this.CallState,
                                                 "Refreshing AT failed either due to one of these :- Internal Server Error,Gateway Timeout and Service Unavailable.Hence returning back stale AT");
                    return(extendedLifetimeResultEx.Result);
                }
                throw;
            }
            finally
            {
                if (notifiedBeforeAccessCache)
                {
                    this.NotifyAfterAccessCache();
                }
            }
        }
        internal AuthenticationResultEx LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState)
        {
            PlatformPlugin.Logger.Verbose(callState, "Looking up cache for a token...");

            AuthenticationResultEx resultEx = null;

            KeyValuePair<TokenCacheKey, AuthenticationResultEx>? kvp = this.LoadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId, callState);

            if (kvp.HasValue)
            {
                TokenCacheKey cacheKey = kvp.Value.Key;
                resultEx = kvp.Value.Value;
                bool tokenNearExpiry = (resultEx.Result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));

                if (tokenNearExpiry)
                {
                    resultEx.Result.AccessToken = null;
                    PlatformPlugin.Logger.Verbose(callState, "An expired or near expiry token was found in the cache");
                }
                else if (!cacheKey.ResourceEquals(resource))
                {
                    PlatformPlugin.Logger.Verbose(callState, 
                        string.Format("Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'", cacheKey.Resource, resource));
                    var newResultEx = new AuthenticationResultEx
                    {
                        Result = new AuthenticationResult(null, null, DateTimeOffset.MinValue),                            
                        RefreshToken = resultEx.RefreshToken,
                        ResourceInResponse = resultEx.ResourceInResponse
                    };

                    newResultEx.Result.UpdateTenantAndUserInfo(resultEx.Result.TenantId, resultEx.Result.IdToken, resultEx.Result.UserInfo);
                    resultEx = newResultEx;
                }
                else
                {
                    PlatformPlugin.Logger.Verbose(callState, string.Format("{0} minutes left until token in cache expires", (resultEx.Result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                }                

                if (resultEx.Result.AccessToken == null && resultEx.RefreshToken == null)
                {
                    this.tokenCacheDictionary.Remove(cacheKey);
                    PlatformPlugin.Logger.Information(callState, "An old item was removed from the cache");
                    this.HasStateChanged = true;
                    resultEx = null;
                }

                if (resultEx != null)
                {
                    PlatformPlugin.Logger.Information(callState, "A matching item (access token or refresh token or both) was found in the cache");
                }
            }
            else
            {
                PlatformPlugin.Logger.Information(callState, "No matching token was found in the cache");
            }

            return resultEx;
        }
        private static void AddToDictionary(TokenCache tokenCache, TokenCacheKey key, AuthenticationResultEx value)
        {
            tokenCache.OnBeforeAccess(new TokenCacheNotificationArgs { TokenCache = tokenCache });
            tokenCache.OnBeforeWrite(new TokenCacheNotificationArgs { TokenCache = tokenCache });
            tokenCache.tokenCacheDictionary.Add(key, value);
            tokenCache.HasStateChanged = true;
            tokenCache.OnAfterAccess(new TokenCacheNotificationArgs { TokenCache = tokenCache });

        }
コード例 #25
0
        public AuthenticationResultEx GetAuthTokenInBackground(AuthenticationRequest request, Activity callerActivity)
        {
            AuthenticationResultEx authResult = null;

            VerifyNotOnMainThread();

            // if there is not any user added to account, it returns empty
            Account targetAccount = null;

            Account[] accountList = mAcctManager
                                    .GetAccountsByType(BrokerConstants.BrokerAccountType);

            if (!string.IsNullOrEmpty(request.BrokerAccountName))
            {
                targetAccount = FindAccount(request.BrokerAccountName, accountList);
            }
            else
            {
                try
                {
                    UserInfo[] users        = GetBrokerUsers();
                    UserInfo   matchingUser = FindUserInfo(request.UserId, users);
                    if (matchingUser != null)
                    {
                        targetAccount = FindAccount(matchingUser.DisplayableId, accountList);
                    }
                }
                catch (Exception e)
                {
                    CallState.Logger.Error(null, e);
                }
            }

            if (targetAccount != null)
            {
                Bundle brokerOptions = GetBrokerOptions(request);

                // blocking call to get token from cache or refresh request in
                // background at Authenticator
                IAccountManagerFuture result = null;
                try
                {
                    // It does not expect activity to be launched.
                    // AuthenticatorService is handling the request at
                    // AccountManager.
                    //
                    result = mAcctManager.GetAuthToken(targetAccount,
                                                       BrokerConstants.AuthtokenType, brokerOptions, false,
                                                       null /*
                                                             * set to null to avoid callback
                                                             */, new Handler(callerActivity.MainLooper));

                    // Making blocking request here
                    CallState.Logger.Verbose(null, "Received result from Authenticator");
                    Bundle bundleResult = (Bundle)result.GetResult(10000, TimeUnit.Milliseconds);
                    // Authenticator should throw OperationCanceledException if
                    // token is not available
                    authResult = GetResultFromBrokerResponse(bundleResult);
                }
                catch (OperationCanceledException e)
                {
                    CallState.Logger.Error(null, e);
                }
                catch (AuthenticatorException e)
                {
                    CallState.Logger.Error(null, e);
                }
                catch (Exception e)
                {
                    // Authenticator gets problem from webrequest or file read/write

                    /*                    Logger.e(TAG, "Authenticator cancels the request", "",
                     *                          ADALError.BROKER_AUTHENTICATOR_IO_EXCEPTION);*/

                    CallState.Logger.Error(null, e);
                }

                CallState.Logger.Verbose(null, "Returning result from Authenticator");
                return(authResult);
            }
            else
            {
                CallState.Logger.Verbose(null, "Target account is not found");
            }

            return(null);
        }
 private static bool AreAuthenticationResultExsEqual(AuthenticationResultEx resultEx1, AuthenticationResultEx resultEx2)
 {
     return AreAuthenticationResultsEqual(resultEx1.Result, resultEx2.Result) &&
         resultEx1.RefreshToken == resultEx2.RefreshToken &&
         resultEx1.IsMultipleResourceRefreshToken == resultEx2.IsMultipleResourceRefreshToken;
 }
コード例 #27
0
        internal void StoreToCache(AuthenticationResultEx result, string authority, string[] scope, string clientId,
            TokenSubjectType subjectType, CallState callState)
        {
            PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache...");

            if (ADALScopeHelper.IsNullOrEmpty(scope) || ADALScopeHelper.CreateSetFromArray(scope).Contains("openid"))
            {
                scope = new[] {clientId};
            }

            string uniqueId = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null;
            string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null;

            this.OnBeforeWrite(new TokenCacheNotificationArgs
            {
                Scope = scope,
                ClientId = clientId,
                UniqueId = uniqueId,
                DisplayableId = displayableId
            });

            TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, scope, clientId, subjectType,
                result.Result.UserInfo);
            // First identify all potential tokens.
            List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> items = this.QueryCache(authority, clientId,
                subjectType, uniqueId, displayableId);
            List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> itemsToRemove =
                items.Where(p => p.Key.ScopeIntersects(scope)).ToList();

            if (!itemsToRemove.Any())
            {
                this.tokenCacheDictionary[tokenCacheKey] = result;
                PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache");
            }
            else
            {
                //remove all intersections
                foreach (var itemToRemove in itemsToRemove)
                {
                    this.tokenCacheDictionary.Remove(itemToRemove);
                }

                this.tokenCacheDictionary[tokenCacheKey] = result;
                PlatformPlugin.Logger.Verbose(callState, "An item was updated in the cache");
            }

            this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType);
            this.HasStateChanged = true;
        }
        internal static void TokenCacheCapacityTest()
        {
            var tokenCache = new TokenCache();
            tokenCache.Clear();

            const int MaxItemCount = 100;
            const int MaxFieldSize = 256;
            TokenCacheKey[] keys = new TokenCacheKey[MaxItemCount];
            AuthenticationResultEx[] values = new AuthenticationResultEx[MaxItemCount];

            for (int i = 0; i < MaxItemCount; i++)
            {
                keys[i] = GenerateRandomTokenCacheKey(MaxFieldSize);

                values[i] = CreateCacheValue(null, null);
                AddToDictionary(tokenCache, keys[i], values[i]);
            }

            Verify.AreEqual(MaxItemCount, tokenCache.Count);

            for (int i = 0; i < MaxItemCount; i++)
            {
                AuthenticationResultEx cacheValue;
                int index = MaxItemCount - i - 1;
                Verify.IsTrue(tokenCache.tokenCacheDictionary.TryGetValue(keys[index], out cacheValue));
                Verify.AreEqual(values[index], cacheValue);
                RemoveFromDictionary(tokenCache, keys[index]);
                Verify.AreEqual(index, tokenCache.Count);
            }

            tokenCache.Clear();
        }
        internal void StoreToCache(AuthenticationResultEx result, string authority, string resource, string clientId, TokenSubjectType subjectType, CallState callState)
        {
            PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache...");

            string uniqueId = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null;
            string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null;

            this.OnBeforeWrite(new TokenCacheNotificationArgs
            {
                Resource = resource,
                ClientId = clientId,
                UniqueId = uniqueId,
                DisplayableId = displayableId
            });

            TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType, result.Result.UserInfo);
            this.tokenCacheDictionary[tokenCacheKey] = result;
            PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache");
            this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType);

            this.HasStateChanged = true;
        }
コード例 #30
0
 protected virtual void PostTokenRequest(AuthenticationResultEx result)
 {
     this.Authenticator.UpdateTenantId(result.Result.TenantId);
 }
コード例 #31
0
        protected override void PostTokenRequest(AuthenticationResultEx resultEx)
        {
            base.PostTokenRequest(resultEx);
            if ((this.DisplayableId == null && this.UniqueId == null) || this.UserIdentifierType == UserIdentifierType.OptionalDisplayableId)
            {
                return;
            }

            string uniqueId = (resultEx.Result.UserInfo != null && resultEx.Result.UserInfo.UniqueId != null) ? resultEx.Result.UserInfo.UniqueId : "NULL";
            string displayableId = (resultEx.Result.UserInfo != null) ? resultEx.Result.UserInfo.DisplayableId : "NULL";

            if (this.UserIdentifierType == UserIdentifierType.UniqueId && string.Compare(uniqueId, this.UniqueId, StringComparison.Ordinal) != 0)
            {
                throw new AdalUserMismatchException(this.UniqueId, uniqueId);
            }

            if (this.UserIdentifierType == UserIdentifierType.RequiredDisplayableId && string.Compare(displayableId, this.DisplayableId, StringComparison.OrdinalIgnoreCase) != 0)
            {
                throw new AdalUserMismatchException(this.DisplayableId, displayableId);
            }
        }
コード例 #32
0
        internal AuthenticationResultEx LoadFromCache(string authority, string[] scope, string clientId,
            TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState)
        {
            PlatformPlugin.Logger.Verbose(callState, "Looking up cache for a token...");
            if (ADALScopeHelper.CreateSetFromArray(scope).Contains(clientId))
            {
                PlatformPlugin.Logger.Verbose(callState, "Looking for id token...");
            }

            AuthenticationResultEx resultEx = null;

            //get either a matching token or an MRRT supported RT
            KeyValuePair<TokenCacheKey, AuthenticationResultEx>? kvp = this.LoadSingleItemFromCache(authority, scope,
                clientId, subjectType, uniqueId, displayableId, callState);

            if (kvp.HasValue)
            {
                TokenCacheKey cacheKey = kvp.Value.Key;
                resultEx = kvp.Value.Value;
                bool tokenNearExpiry = (resultEx.Result.ExpiresOn <=
                                        DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));

                if (tokenNearExpiry)
                {
                    resultEx.Result.Token = null;
                    PlatformPlugin.Logger.Verbose(callState, "An expired or near expiry token was found in the cache");
                }
                else if (!cacheKey.ScopeContains(scope))
                {
                    //requested scope are not a subset.
                    PlatformPlugin.Logger.Verbose(callState,
                        string.Format("Refresh token for scope '{0}' will be used to acquire token for '{1}'",
                            ADALScopeHelper.CreateSingleStringFromArray(cacheKey.Scope),
                            ADALScopeHelper.CreateSingleStringFromArray(scope)));
                    var newResultEx = new AuthenticationResultEx
                    {
                        Result = new AuthenticationResult(null, null, DateTimeOffset.MinValue),
                        RefreshToken = resultEx.RefreshToken,
                        ScopeInResponse = resultEx.ScopeInResponse
                    };

                    newResultEx.Result.UpdateTenantAndUserInfo(resultEx.Result.TenantId, resultEx.Result.ProfileInfo,
                        resultEx.Result.UserInfo);
                    resultEx = newResultEx;
                }
                else
                {
                    PlatformPlugin.Logger.Verbose(callState,
                        string.Format("{0} minutes left until token in cache expires",
                            (resultEx.Result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                }

                if (resultEx.Result.Token == null && resultEx.RefreshToken == null)
                {
                    this.tokenCacheDictionary.Remove(cacheKey);
                    PlatformPlugin.Logger.Information(callState, "An old item was removed from the cache");
                    this.HasStateChanged = true;
                    resultEx = null;
                }

                if (resultEx != null)
                {
                    PlatformPlugin.Logger.Information(callState,
                        "A matching item (access token or refresh token or both) was found in the cache");
                }
            }
            else
            {
                PlatformPlugin.Logger.Information(callState, "No matching token was found in the cache");
            }

            return resultEx;
        }
コード例 #33
0
        internal AuthenticationResultEx LoadFromCache(CacheQueryData cacheQueryData, CallState callState)
        {
            lock (cacheLock)
            {
                PlatformPlugin.Logger.Verbose(callState, "Looking up cache for a token...");

                AuthenticationResultEx resultEx = null;
                KeyValuePair <TokenCacheKey, AuthenticationResultEx>?kvp = this.LoadSingleItemFromCache(cacheQueryData, callState);

                if (kvp.HasValue)
                {
                    TokenCacheKey cacheKey = kvp.Value.Key;
                    resultEx = kvp.Value.Value.Clone();

                    bool tokenNearExpiry = (resultEx.Result.ExpiresOn <=
                                            DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));
                    bool tokenExtendedLifeTimeExpired = (resultEx.Result.ExtendedExpiresOn <=
                                                         DateTime.UtcNow);

                    //check for cross-tenant authority
                    if (!cacheKey.Authority.Equals(cacheQueryData.Authority))
                    {
                        // this is a cross-tenant result. use RT only
                        resultEx.Result.AccessToken = null;
                        PlatformPlugin.Logger.Information(callState,
                                                          "Cross Tenant refresh token was found in the cache");
                    }
                    else if (tokenNearExpiry && !cacheQueryData.ExtendedLifeTimeEnabled)
                    {
                        resultEx.Result.AccessToken = null;
                        PlatformPlugin.Logger.Information(callState,
                                                          "An expired or near expiry token was found in the cache");
                    }
                    else if (!cacheKey.ResourceEquals(cacheQueryData.Resource))
                    {
                        PlatformPlugin.Logger.Information(callState,
                                                          string.Format(CultureInfo.CurrentCulture,
                                                                        "Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'",
                                                                        cacheKey.Resource, cacheQueryData.Resource));
                        var newResultEx = new AuthenticationResultEx
                        {
                            Result             = new AuthenticationResult(null, null, DateTimeOffset.MinValue),
                            RefreshToken       = resultEx.RefreshToken,
                            ResourceInResponse = resultEx.ResourceInResponse
                        };

                        newResultEx.Result.UpdateTenantAndUserInfo(resultEx.Result.TenantId, resultEx.Result.IdToken,
                                                                   resultEx.Result.UserInfo);
                        resultEx = newResultEx;
                    }
                    else if (!tokenExtendedLifeTimeExpired && cacheQueryData.ExtendedLifeTimeEnabled && tokenNearExpiry)
                    {
                        resultEx.Result.ExtendedLifeTimeToken = true;
                        resultEx.Result.ExpiresOn             = resultEx.Result.ExtendedExpiresOn;
                        PlatformPlugin.Logger.Information(callState,
                                                          "The extendedLifeTime is enabled and a stale AT with extendedLifeTimeEnabled is returned.");
                    }
                    else if (tokenExtendedLifeTimeExpired)
                    {
                        resultEx.Result.AccessToken = null;
                        PlatformPlugin.Logger.Information(callState,
                                                          "The AT has expired its ExtendedLifeTime");
                    }
                    else
                    {
                        PlatformPlugin.Logger.Information(callState,
                                                          string.Format(CultureInfo.CurrentCulture, "{0} minutes left until token in cache expires",
                                                                        (resultEx.Result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                    }

                    if (resultEx.Result.AccessToken == null && resultEx.RefreshToken == null)
                    {
                        this.tokenCacheDictionary.Remove(cacheKey);
                        PlatformPlugin.Logger.Information(callState, "An old item was removed from the cache");
                        this.HasStateChanged = true;
                        resultEx             = null;
                    }

                    if (resultEx != null)
                    {
                        PlatformPlugin.Logger.Information(callState,
                                                          "A matching item (access token or refresh token or both) was found in the cache");
                    }
                }
                else
                {
                    PlatformPlugin.Logger.Information(callState, "No matching token was found in the cache");
                }

                return(resultEx);
            }
        }
コード例 #34
0
 protected virtual void PostTokenRequest(AuthenticationResultEx result)
 {
     this.Authenticator.UpdateTenantId(result.Result.TenantId);
 }
 private static void VerifyAuthenticationResultExsAreNotEqual(AuthenticationResultEx resultEx1, AuthenticationResultEx resultEx2)
 {
     Verify.IsFalse(AreAuthenticationResultExsEqual(resultEx1, resultEx2));
 }
コード例 #36
0
        private void UpdateCachedMrrtRefreshTokens(AuthenticationResultEx result, string authority, string clientId,
            TokenSubjectType subjectType)
        {
            if (result.Result.UserInfo != null && result.IsMultipleResourceRefreshToken)
            {
                List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> mrrtItems =
                    this.QueryCache(authority, clientId, subjectType, result.Result.UserInfo.UniqueId,
                        result.Result.UserInfo.DisplayableId)
                        .Where(p => p.Value.IsMultipleResourceRefreshToken)
                        .ToList();

                foreach (KeyValuePair<TokenCacheKey, AuthenticationResultEx> mrrtItem in mrrtItems)
                {
                    mrrtItem.Value.RefreshToken = result.RefreshToken;
                }
            }
        }