Esempio n. 1
0
        /// <summary>
        /// Creates security token.
        /// </summary>
        /// <param name="tokenDescriptor">The token descriptor.</param>
        /// <returns>Security token.</returns>
        public override SecurityToken CreateToken(SecurityTokenDescriptor tokenDescriptor)
        {
            if (tokenDescriptor == null)
            {
                throw new ArgumentNullException("tokenDescriptor");
            }

            // See details in Json Web Token specification.
            var seconds = (tokenDescriptor.Lifetime.Expires - tokenDescriptor.Lifetime.Created) ?? new TimeSpan(0, 0, 3600);
            var header  = new JwtHeaderSegment();
            var claims  = new JwtClaimsSegment(
                tokenDescriptor.TokenIssuerName,
                tokenDescriptor.AppliesToAddress,
                DateTime.UtcNow,
                DateTime.UtcNow + seconds,
                tokenDescriptor.Subject.Claims
                );

            // See details in Json Web Signature specification.
            var key             = (InMemorySymmetricSecurityKey)tokenDescriptor.SigningCredentials.SigningKey;
            var mac             = new HMACSHA256(key.GetSymmetricKey());
            var hash            = mac.ComputeHash(Encoding.UTF8.GetBytes(JsonWebToken.GetSigningInput(header, claims)));
            var jwsCryptoOutput = JwtTokenUtility.Base64UrlEncode(hash);

            return(new JsonWebToken(header, claims, jwsCryptoOutput));
        }
Esempio n. 2
0
        /// <summary>
        /// Parses JWT.
        /// </summary>
        /// <param name="rawToken">Raw JWT encoded in base64 url encoding.</param>
        /// <returns>New instance of <see cref="JsonWebToken"/>.</returns>
        /// <remarks>For details refer to Json Web Token specification.</remarks>
        internal static JsonWebToken ParseRawToken(string rawToken)
        {
            JsonWebToken result = null;

            var tokenParts = rawToken.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);

            if (tokenParts.Length > 3 || tokenParts.Length < 2)
            {
                throw new SecurityTokenException("Invalid token format.");
            }

            var rawJwtHeader = Encoding.UTF8.GetString(JwtTokenUtility.Base64UrlDecode(tokenParts[0]));
            var rawJwtClaims = Encoding.UTF8.GetString(JwtTokenUtility.Base64UrlDecode(tokenParts[1]));
            var signature    = tokenParts.Length > 2 ? tokenParts[2] : string.Empty;

            try
            {
                var headerSegment = JsonConvert.DeserializeObject <JwtHeaderSegment>(rawJwtHeader);
                var claimsSegment = JsonConvert.DeserializeObject <JwtClaimsSegment>(rawJwtClaims);

                result = new JsonWebToken(headerSegment, claimsSegment, signature);
            }
            catch (Exception ex)
            {
                throw new SecurityTokenException("Failed to parse token", ex);
            }

            return(result);
        }
Esempio n. 3
0
        /// <summary>
        /// Retrieves token signing input.
        /// </summary>
        /// <param name="header">JWT header section.</param>
        /// <param name="payload">JWT payload section.</param>
        /// <returns>Signing input.</returns>
        /// <remarks>For details refer to Json Web Signature specification.</remarks>
        internal static string GetSigningInput(JwtHeaderSegment header, JwtClaimsSegment payload)
        {
            var decodedJwsHeaderInput = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header));
            var jwsHeaderInput        = JwtTokenUtility.Base64UrlEncode(decodedJwsHeaderInput);

            var decodedJwsPayloadInput = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload));
            var jwsPaloadInput         = JwtTokenUtility.Base64UrlEncode(decodedJwsPayloadInput);

            return(string.Format("{0}.{1}", jwsHeaderInput, jwsPaloadInput));
        }
Esempio n. 4
0
        public override void WriteToken(XmlWriter writer, SecurityToken token)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }

            // Json Web Token is presented in binary (to quite binary but whatever) format.
            // WIF does not care about it, WS-* stack works only with XML. Thus, just
            // wrapping our JWT with XML.
            var wrappedElement =
                JwtTokenUtility.WrapInsideBinarySecurityToken(((JsonWebToken)token).GetRawToken());

            wrappedElement.WriteTo(writer);
        }
Esempio n. 5
0
        /// <summary>
        /// Validates security token.
        /// </summary>
        /// <param name="token">Security token.</param>
        /// <returns><see cref="ClaimsIdentityCollection"/> stored inside security token.</returns>
        public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }

            var jwt = (JsonWebToken)token;

            // Stage 1: Validating token signature.
            InMemorySymmetricSecurityKey key = null;

            try
            {
                key = (InMemorySymmetricSecurityKey)Configuration.IssuerTokenResolver.ResolveSecurityKey(
                    new KeyNameIdentifierClause(jwt.ClaimsSection.Issuer)
                    );
            }
            catch (Exception)
            {
                throw new InvalidOperationException("Failed to resolver isser's key");
            }

            // Signature is checked according to JSON Web Signature specification.
            var mac = new HMACSHA256(key.GetSymmetricKey());

            var cryptoInput = JwtTokenUtility.Base64UrlEncode(
                mac.ComputeHash(Encoding.UTF8.GetBytes(jwt.GetSigningInput()))
                );

            if (!string.Equals(jwt.Signature, cryptoInput, StringComparison.Ordinal))
            {
                throw new SignatureVerificationFailedException("Token contents do not match signature.");
            }

            // Stage 2: Checking whether token is up to date.
            var utcNow = DateTime.UtcNow;

            if (utcNow + Configuration.MaxClockSkew < token.ValidFrom)
            {
                throw new SecurityTokenNotYetValidException();
            }

            if (utcNow + Configuration.MaxClockSkew > token.ValidTo)
            {
                throw new SecurityTokenExpiredException();
            }

            // Stage 3: Checking whether we should even bother talking to specified RP.
            if (Configuration.AudienceRestriction.AudienceMode != AudienceUriMode.Never)
            {
                if (string.IsNullOrWhiteSpace(jwt.ClaimsSection.Audience))
                {
                    throw new AudienceUriValidationFailedException("Token does not contain Audience uri.");
                }

                var uri = new Uri(jwt.ClaimsSection.Audience);

                if (!Configuration.AudienceRestriction.AllowedAudienceUris.Contains(uri))
                {
                    throw new AudienceUriValidationFailedException(
                              string.Format("Uri {0} is not spceified in audience uri section", uri.ToString())
                              );
                }
            }

            // Stage 4: If configured, let WIF check "Replay Token" attack.
            if (Configuration.DetectReplayedTokens)
            {
                DetectReplayedTokens(token);
            }

            // Stage 5: Extracting claims from security token.
            var inputIdentity = new ClaimsIdentity(jwt.ClaimsSection.Claims);

            // Stage 6: If configured, saving bootstrap token that may be
            // used by RP for delegation (ActAs and BehalfOf calls).
            if (Configuration.SaveBootstrapTokens)
            {
                inputIdentity.BootstrapToken = token;
            }

            return(new ClaimsIdentityCollection(new [] { inputIdentity }));
        }
Esempio n. 6
0
        /// <summary>
        /// Processes the request.
        /// </summary>
        /// <param name="requestContext">The request context.</param>
        public override void ProcessRequest(ref RequestContext requestContext)
        {
            // This is place where all WIF magic happens. For normal SOAP services
            // WIF pipeline will handle all this stuff behind the scenes. For
            // RESTful services we have to intercept request before it reaches
            // WIF pipeline and perform all requiered actions ourself.

            try
            {
                var httpRequest =
                    requestContext.RequestMessage.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
                if (httpRequest == null)
                {
                    throw new WebFaultException(HttpStatusCode.BadRequest);
                }

                string accessToken = null;

                try
                {
                    // Extracting raw token from Authorization HTTP header.
                    accessToken = ExtractToken(httpRequest.Headers[HttpRequestHeader.Authorization]);
                    if (string.IsNullOrWhiteSpace(accessToken))
                    {
                        throw new WebFaultException(HttpStatusCode.Unauthorized);
                    }
                }
                catch (WebFaultException)
                {
                    throw;
                }
                catch (Exception)
                {
                    throw new WebFaultException(HttpStatusCode.BadRequest);
                }

                // Wrapping parsed JWT inside XML envelope so WIF would be able to handle it.
                var wrappedToken = JwtTokenUtility.WrapInsideBinarySecurityToken(accessToken);

                using (var reader = wrappedToken.CreateReader())
                {
                    // Code bellow performs same actions as WIF pipeline does.

                    // Defining list of token handlers that can be used to validate incoming token.
                    var handlersCollection =
                        _wifCredentials.SecurityTokenHandlerCollectionManager[SecurityTokenHandlerCollectionManager.Usage.Default];

                    if (!handlersCollection.CanReadToken(reader))
                    {
                        throw new InvalidOperationException("Security token handler is not found.");
                    }

                    var token      = handlersCollection.ReadToken(reader);
                    var identities = handlersCollection.ValidateToken(token);

                    var principal = _wifCredentials.ClaimsAuthenticationManager.Authenticate(
                        httpRequest.Method,
                        new ClaimsPrincipal(identities)
                        );
                    var identityCollection = principal != null ? principal.Identities : new ClaimsIdentityCollection();

                    // Creating authorization context. This code will set Thread.CurrentPrincipal
                    // to ClaimsPrincipal defined by security token.
                    var authorizationContext =
                        new List <IAuthorizationPolicy> {
                        new AuthorizationPolicy(identityCollection)
                    }.AsReadOnly();
                    var security = SecurityMessageProperty.GetOrCreate(requestContext.RequestMessage);
                    security.ServiceSecurityContext = new ServiceSecurityContext(authorizationContext);
                }
            }
            catch (Exception)
            {
                throw new WebFaultException(HttpStatusCode.BadRequest);
            }
        }