Пример #1
0
        public async Task RetrieveAsync(OioIdwsMatchEndpointContext context)
        {
            var clientCertificate = context.ClientCertificate();

            if (clientCertificate?.Thumbprint == null ||
                context.Options.TrustedWspCertificateThumbprints == null ||
                !context.Options.TrustedWspCertificateThumbprints
                .Any(x => clientCertificate.Thumbprint.Equals(x, StringComparison.OrdinalIgnoreCase)))
            {
                RequestFailed(context, 401, "No trusted client certificate was provided");
                return;
            }

            context.Response.ContentType = "application/json; charset=UTF-8";

            if (!context.Request.QueryString.HasValue)
            {
                RequestFailed(context, 400, "access token must be given as the query string");
                return;
            }

            var accessToken = context.Request.QueryString.Value;

            _logger.WriteEntry(Log.ProcessingToken(accessToken));

            AuthenticationProperties tokenProperties;

            try
            {
                tokenProperties = context.Options.TokenDataFormat.Unprotect(accessToken);
            }
            catch (Exception ex)
            {
                RequestFailed(context, 401, "Token could not be read", ex);
                return;
            }

            if (tokenProperties == null)
            {
                RequestFailed(context, 401, "Token could not be unprotected");
                return;
            }

            //check the Expires that was stored inside the protected access token, saving a round trip to the SecurityTokenStore if the token is expired
            if (tokenProperties.ExpiresUtc.GetValueOrDefault() + context.Options.MaxClockSkew < context.Options.SystemClock.UtcNow)
            {
                TokenExpired(context, accessToken);
                return;
            }

            var tokenValue = tokenProperties.Value();

            _logger.WriteEntry(Log.AttemptRetrieveInformationForAccessToken(tokenValue));
            var token = await _securityTokenStore.RetrieveTokenAsync(tokenValue);

            if (token == null)
            {
                _logger.WriteEntry(Log.CouldNotRetrieveTokenInformationFromStore());
                context.Response.StatusCode = 404;
                return;
            }

            // we might as well check expiry against that stored along with the token information even that we know that OioIdwsToken from token store always have the same expiry time as the access token ... this is set set in the AccessTokenIssuer.IssueAsync().
            if (token.ExpiresUtc + context.Options.MaxClockSkew < context.Options.SystemClock.UtcNow)
            {
                TokenExpired(context, accessToken);
                return;
            }

            var serializer = new JsonSerializer();

            using (var writer = new StreamWriter(context.Response.Body))
            {
                serializer.Serialize(writer, token);
            }

            _logger.WriteEntry(Log.ProcessingTokenCompleted(accessToken));

            context.RequestCompleted();
        }
Пример #2
0
        public async Task IssueAsync(OioIdwsMatchEndpointContext context)
        {
            if (string.IsNullOrEmpty(context.Request.ContentType))
            {
                SetInvalidRequest(context, "No content type was specified");
                return;
            }

            var ct = new System.Net.Mime.ContentType(context.Request.ContentType);

            var validContentType = "application/x-www-form-urlencoded";

            if (!ct.MediaType.Equals(validContentType, StringComparison.InvariantCultureIgnoreCase))
            {
                SetInvalidRequest(context, $"Content type '{validContentType}' is required.");
                return;
            }

            var form = await context.Request.ReadFormAsync();

            var tokenValueBase64 = form["saml-token"];

            if (string.IsNullOrEmpty(tokenValueBase64))
            {
                SetInvalidRequest(context, "saml-token was missing");
                return;
            }

            string tokenValue;

            try
            {
                var bytes = Convert.FromBase64String(tokenValueBase64);
                using (var stream = new MemoryStream(bytes))
                {
                    using (var reader = new StreamReader(stream))
                    {
                        tokenValue = await reader.ReadToEndAsync();
                    }
                }
            }
            catch (Exception)
            {
                SetInvalidRequest(context, "saml-token must be in base64");
                return;
            }

            var clientCertificate = context.ClientCertificate();

            _logger.WriteEntry(Log.StartingTokenValidation());
            var samlTokenValidation = await _tokenValidator.ValidateTokenAsync(tokenValue, clientCertificate, context.Options);

            if (!samlTokenValidation.Success)
            {
                _logger.WriteEntry(Log.IssuingTokenDenied(samlTokenValidation.ErrorDescription, samlTokenValidation.ValidationException));

                // Scheme is mandatory and Holder-Of-Key is currently the only supportede scheme at NemLog-in STS. Hence, we specify Holder-Of-Key.
                context.Response.SetAuthenticationFailed(AccessTokenType.HolderOfKey, AuthenticationErrorCodes.InvalidToken, samlTokenValidation.ErrorDescription);
                context.RequestCompleted();
                return;
            }

            _logger.WriteEntry(Log.TokenValidationCompleted());

            var expiresIn = context.Options.AccessTokenExpiration;

            int requestedExpiration;

            if (int.TryParse(form["should-expire-in"], out requestedExpiration))
            {
                var tmp = TimeSpan.FromSeconds(requestedExpiration);

                if (tmp < expiresIn)
                {
                    //if the client wants a lower expiration, that's ok. Never to increase it.
                    expiresIn = tmp;
                }
            }

            var storedToken = new OioIdwsToken
            {
                CertificateThumbprint = samlTokenValidation.AccessTokenType == AccessTokenType.HolderOfKey
                    ? clientCertificate?.Thumbprint?.ToLowerInvariant()
                    : null,
                Type       = samlTokenValidation.AccessTokenType,
                ExpiresUtc = context.Options.SystemClock.UtcNow + expiresIn,
                Claims     = samlTokenValidation.ClaimsIdentity.Claims.Select(x => new OioIdwsClaim
                {
                    Type      = x.Type,
                    Value     = x.Value,
                    Issuer    = x.Issuer,
                    ValueType = x.ValueType
                }).ToList(),
            };

            var accessToken = await GenerateAccessTokenAsync(context, storedToken);

            await WriteAccessTokenAsync(context.Response, accessToken, samlTokenValidation.AccessTokenType, expiresIn);

            _logger.WriteEntry(Log.TokenIssuedWithExpiration(accessToken, expiresIn));

            context.RequestCompleted();
        }