Exemple #1
0
        public async Task RefreshToken(JwtSecurityToken jwt, TokenBaseAttribute attribute)
        {
            if (string.IsNullOrEmpty(attribute.Resource))
            {
                throw new ArgumentException("A resource is required to renew an access token.");
            }

            if (string.IsNullOrEmpty(attribute.UserId))
            {
                throw new ArgumentException("A userId is required to renew an access token.");
            }

            if (string.IsNullOrEmpty(attribute.IdentityProvider))
            {
                throw new ArgumentException("A provider is necessary to renew an access token.");
            }

            string refreshUrl = $"https://{_options.HostName}/.auth/refresh?resource=" + WebUtility.UrlEncode(attribute.Resource);

            using (var refreshRequest = new HttpRequestMessage(HttpMethod.Get, refreshUrl))
            {
                refreshRequest.Headers.Add("x-zumo-auth", jwt.RawData);
                _log.LogTrace($"Refreshing ${attribute.IdentityProvider} access token for user ${attribute.UserId} at ${refreshUrl}");
                using (HttpResponseMessage response = await _httpClient.SendAsync(refreshRequest))
                {
                    _log.LogTrace($"Response from ${refreshUrl}: {response.StatusCode}");
                    if (!response.IsSuccessStatusCode)
                    {
                        string errorResponse = await response.Content.ReadAsStringAsync();

                        throw new InvalidOperationException($"Failed to refresh {attribute.UserId} {attribute.IdentityProvider} error={response.StatusCode} {errorResponse}");
                    }
                }
            }
        }
        private JwtSecurityToken CreateTokenForEasyAuthAccess(TokenBaseAttribute attribute)
        {
            if (string.IsNullOrEmpty(attribute.UserId))
            {
                throw new ArgumentException("A userId is required to obtain an access token.");
            }

            if (string.IsNullOrEmpty(attribute.IdentityProvider))
            {
                throw new ArgumentException("A provider is necessary to obtain an access token.");
            }

            var identityClaims = new ClaimsIdentity(attribute.UserId);

            identityClaims.AddClaim(new Claim(ClaimTypes.NameIdentifier, attribute.UserId));
            identityClaims.AddClaim(new Claim("idp", attribute.IdentityProvider));

            var baseUrl = $"https://{_options.HostName}/";
            var descr   = new SecurityTokenDescriptor
            {
                Audience           = baseUrl,
                Issuer             = baseUrl,
                Subject            = identityClaims,
                Expires            = DateTime.UtcNow.AddMinutes(JwtTokenDurationInMinutes),
                SigningCredentials = new HmacSigningCredentials(_options.SigningKey),
            };

            return((JwtSecurityToken)JwtHandler.CreateToken(descr));
        }
        /// <summary>
        /// Retrieve Easy Auth token based on provider & principal ID
        /// </summary>
        /// <param name="attribute">The metadata for the token to grab</param>
        /// <returns>Task with Token Store entry of the token</returns>
        public async Task <string> GetEasyAuthAccessTokenAsync(TokenBaseAttribute attribute)
        {
            var jwt = CreateTokenForEasyAuthAccess(attribute);
            EasyAuthTokenStoreEntry tokenStoreEntry = await _client.GetTokenStoreEntry(jwt, attribute);

            bool isTokenValid   = IsTokenValid(tokenStoreEntry.AccessToken);
            bool isTokenExpired = tokenStoreEntry.ExpiresOn <= DateTime.UtcNow.AddMinutes(GraphTokenBufferInMinutes);
            bool isRefreshable  = IsRefreshableProvider(attribute.IdentityProvider);

            if (isRefreshable && (isTokenExpired || !isTokenValid))
            {
                await _client.RefreshToken(jwt, attribute);

                // Now that the refresh has occured, grab the new token
                tokenStoreEntry = await _client.GetTokenStoreEntry(jwt, attribute);
            }

            return(tokenStoreEntry.AccessToken);
        }
        public async Task <string> ConvertAsync(TokenBaseAttribute attribute, CancellationToken cancellationToken)
        {
            attribute.CheckValidity();
            switch (attribute.Identity)
            {
            case TokenIdentityMode.UserFromId:
                // If the attribute has no identity provider, assume AAD
                attribute.IdentityProvider = attribute.IdentityProvider ?? "AAD";
                var easyAuthTokenManager = new EasyAuthTokenManager(_easyAuthClient, _options);
                return(await easyAuthTokenManager.GetEasyAuthAccessTokenAsync(attribute));

            case TokenIdentityMode.UserFromToken:
                return(await GetAuthTokenFromUserToken(attribute.UserToken, attribute.Resource));

            case TokenIdentityMode.ClientCredentials:
                return(await _aadManager.GetTokenFromClientCredentials(attribute.Resource));
            }

            throw new InvalidOperationException("Unable to authorize without Principal ID or ID Token.");
        }
Exemple #5
0
        public async Task <EasyAuthTokenStoreEntry> GetTokenStoreEntry(JwtSecurityToken jwt, TokenBaseAttribute attribute)
        {
            // Send the token to the local /.auth/me endpoint and return the JSON
            string meUrl = $"https://{_options.HostName}/.auth/me?provider={attribute.IdentityProvider}";

            using (var request = new HttpRequestMessage(HttpMethod.Get, meUrl))
            {
                request.Headers.Add("x-zumo-auth", jwt.RawData);
                _log.LogTrace($"Fetching user token data from {meUrl}");
                using (HttpResponseMessage response = await _httpClient.SendAsync(request))
                {
                    _log.LogTrace($"Response from '${meUrl}: {response.StatusCode}");
                    if (!response.IsSuccessStatusCode)
                    {
                        string errorResponse = await response.Content.ReadAsStringAsync();

                        throw new InvalidOperationException($"Request to {meUrl} failed. Status Code: {response.StatusCode}; Body: {errorResponse}");
                    }
                    var responseString = await response.Content.ReadAsStringAsync();

                    return(JsonConvert.DeserializeObject <EasyAuthTokenStoreEntry>(responseString));
                }
            }
        }
        /// <summary>
        /// Either retrieve existing GSC or create a new one
        /// GSCs are cached using a combination of the user's principal ID and the scopes of the token used to authenticate
        /// </summary>
        /// <param name="attribute">Token attribute with either principal ID or ID token</param>
        /// <returns>Authenticated GSC</returns>
        public virtual async Task <IGraphServiceClient> GetMSGraphClientFromTokenAttributeAsync(TokenBaseAttribute attribute, CancellationToken cancellationToken)
        {
            string token = await this._tokenProvider.ConvertAsync(attribute, cancellationToken);

            string principalId = GetTokenOID(token);

            var key = string.Concat(principalId, " ", GetTokenOrderedScopes(token));

            CachedClient cachedClient = null;

            // Check to see if there already exists a GSC associated with this principal ID and the token scopes.
            if (_clients.TryGetValue(key, out cachedClient))
            {
                // Check if token is expired
                if (cachedClient.expirationDate < DateTimeOffset.Now.ToUnixTimeSeconds())
                {
                    // Need to update the client's token & expiration date
                    // $$ todo -- just reset token instead of whole new authentication provider?
                    _clientProvider.UpdateGraphServiceClientAuthToken(cachedClient.client, token);
                    cachedClient.expirationDate = GetTokenExpirationDate(token);
                }

                return(cachedClient.client);
            }
            else
            {
                cachedClient = new CachedClient
                {
                    client         = _clientProvider.CreateNewGraphServiceClient(token),
                    expirationDate = GetTokenExpirationDate(token),
                };
                _clients.TryAdd(key, cachedClient);
                return(cachedClient.client);
            }
        }