public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (!payload.TryGetClaim(JwtClaimNames.Exp.EncodedUtf8Bytes, out var expires))
            {
                error = TokenValidationError.MissingClaim(JwtClaimNames.Exp.ToString());
                return(false);
            }

            if (!payload.TryGetClaim(JwtClaimNames.Jti.EncodedUtf8Bytes, out var jti))
            {
                error = TokenValidationError.MissingClaim(JwtClaimNames.Jti.ToString());
                return(false);
            }

            if (!_tokenReplayCache.TryAdd(jti.GetString(), expires.GetInt64()))
            {
                error = TokenValidationError.TokenReplayed();
                return(false);
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out error);
#else
            error = default;
#endif
            return(true);
        }
Beispiel #2
0
 private Jwt(JwtHeaderDocument header, Jwt nested, byte[] rented)
 {
     _header  = header;
     _payload = nested.Payload;
     _nested  = nested;
     _rented  = rented;
 }
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload is null)
            {
                error = TokenValidationError.MalformedToken();
                return(false);
            }

            if (!payload.TryGetClaim(_claim, out var claim))
            {
                error = TokenValidationError.MissingClaim(_claim);
                return(false);
            }

            if (!claim.TryGetDouble(out var value) || _value != value)
            {
                error = TokenValidationError.InvalidClaim(_claim);
                return(false);
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out error);
#else
            error = default;
#endif
            return(true);
        }
        /// <summary>Try to validate the token header, according to the <paramref name="header"/>.</summary>
        /// <returns><c>true</c> if the <paramref name="header"/> is valid. <c>false</c> otherwise.</returns>
        public bool TryValidateHeader(JwtHeaderDocument header, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (!IgnoreCriticalHeader)
            {
                if (!header.Crit.IsEmpty)
                {
                    var handlers = CriticalHandlers;
                    foreach (var critHeader in header.Crit.EnumerateArray <string>())
                    {
                        var critHeaderName = critHeader.GetString() !;
                        if (!handlers.TryGetValue(critHeaderName, out var handler))
                        {
                            error = TokenValidationError.CriticalHeaderUnsupported(critHeaderName);
                            goto Error;
                        }


                        if (!handler.TryHandle(header, critHeaderName))
                        {
                            error = TokenValidationError.InvalidHeader(critHeaderName);
                            goto Error;
                        }
                    }
                }
            }

            error = null;
            return(true);

Error:
            return(false);
        }
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (header is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.header);
            }

            if (header.Alg.IsEmpty)
            {
                error = TokenValidationError.MissingHeader(JwtHeaderParameterNames.Alg.ToString());
                return(false);
            }

            if (!header.Alg.ValueEquals(_algorithm))
            {
                error = TokenValidationError.InvalidHeader(JwtHeaderParameterNames.Alg.ToString());
                return(false);
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out error);
#else
            error = default;
#endif
            return(true);
        }
Beispiel #6
0
 private Jwt(JwtHeaderDocument header, Jwt nested, TokenValidationError error, byte[] rented)
 {
     _header  = header;
     _payload = nested.Payload;
     _nested  = nested;
     _error   = error;
     _rented  = rented;
 }
Beispiel #7
0
 internal Jwt(Jwt other)
 {
     _rawValue = other._rawValue;
     _rented   = other._rented;
     _header   = other._header;
     _payload  = other._payload;
     _nested   = other._nested;
     _error    = other._error;
 }
            public override bool TryValidateSignature(JwtHeaderDocument header, JwtPayloadDocument payload, ReadOnlySpan <byte> contentBytes, ReadOnlySpan <byte> signatureSegment, [NotNullWhen(false)] out SignatureValidationError?error)
            {
#if NET5_0_OR_GREATER
                Unsafe.SkipInit(out error);
#else
                error = default;
#endif
                return(true);
            }
            public override bool TryValidateSignature(JwtHeaderDocument header, JwtPayloadDocument payload, ReadOnlySpan <byte> contentBytes, ReadOnlySpan <byte> signatureSegment, [NotNullWhen(false)] out SignatureValidationError?error)
            {
                if (!payload.Iss.IsEmpty && payload.Iss.ValueEquals(_issuer))
                {
                    return(_policy.TryValidateSignature(header, payload, contentBytes, signatureSegment, out error));
                }

                error = SignatureValidationError.InvalidSignature();
                return(false);
            }
Beispiel #10
0
        /// <inheritsdoc />
        public Jwk[] GetKeys(JwtHeaderDocument header)
        {
            if (_disposed)
            {
                ThrowHelper.ThrowObjectDisposedException(typeof(CachedKeyProvider));
            }

            var  kid       = header.Kid;
            long now       = EpochTime.UtcNow;
            bool forceSync = false;

            if (_syncAfter > now)
            {
                var keys = _currentJwks.GetKeys(kid);
                if (keys.Length != 0)
                {
                    return(keys);
                }

                // force the refresh only when the latest forced refresh is not too old
                if (_forcedSyncAfter <= now)
                {
                    _forcedSyncAfter = now + MinimumRefreshInterval;
                    forceSync        = true;
                }
            }

            if (forceSync || _syncAfter <= now)
            {
                Jwks previous = _currentJwks;
                Jwks refreshedJwks;
                _refreshLock.Wait();
                try
                {
                    if (forceSync || _syncAfter <= now)
                    {
                        refreshedJwks = GetKeysFromSource();
                        _currentJwks  = refreshedJwks;
                        _syncAfter    = now + AutomaticRefreshInterval;
                        Jwks.PublishJwksRefreshed(previous, refreshedJwks);
                    }
                }
                catch
                {
                    _syncAfter = now + Math.Min(AutomaticRefreshInterval, MinimumRefreshInterval);
                    throw;
                }
                finally
                {
                    _refreshLock.Release();
                }
            }

            return(_currentJwks.GetKeys(kid));
        }
Beispiel #11
0
            public override bool TryValidateSignature(JwtHeaderDocument header, JwtPayloadDocument payload, ReadOnlySpan <byte> contentBytes, ReadOnlySpan <byte> signatureSegment, [NotNullWhen(false)] out SignatureValidationError?error)
            {
                if ((contentBytes.Length == 0 && signatureSegment.Length == 0) ||
                    (signatureSegment.IsEmpty && !header.Alg.IsEmpty && header.Alg.ValueEquals(SignatureAlgorithm.None.Utf8Name)))
                {
                    error = null;
                    return(true);
                }

                error = SignatureValidationError.InvalidSignature();
                return(false);
            }
            public override bool TryValidateSignature(JwtHeaderDocument header, JwtPayloadDocument payload, ReadOnlySpan <byte> contentBytes, ReadOnlySpan <byte> signatureSegment, [NotNullWhen(false)] out SignatureValidationError?error)
            {
                if (!payload.Iss.IsEmpty)
                {
                    if (TryGetPolicy(payload.Iss, out var policy))
                    {
                        return(policy.TryValidateSignature(header, payload, contentBytes, signatureSegment, out error));
                    }
                }

                return(_defaultPolicy.TryValidateSignature(header, payload, contentBytes, signatureSegment, out error));
            }
            public override bool TryValidateSignature(JwtHeaderDocument header, JwtPayloadDocument payload, ReadOnlySpan <byte> contentBytes, ReadOnlySpan <byte> signatureSegment, [NotNullWhen(false)] out SignatureValidationError?error)
            {
                if ((contentBytes.Length == 0 && signatureSegment.Length == 0) ||
                    (signatureSegment.IsEmpty && !header.Alg.IsEmpty && header.Alg.ValueEquals(SignatureAlgorithm.None.Utf8Name)))
                {
#if NET5_0_OR_GREATER
                    Unsafe.SkipInit(out error);
#else
                    error = default;
#endif
                    return(true);
                }

                error = SignatureValidationError.InvalidSignature();
                return(false);
            }
Beispiel #14
0
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload is null)
            {
                error = TokenValidationError.MalformedToken();
                return(false);
            }

            if (payload.ContainsClaim(OAuth2Claims.AuthTime.EncodedUtf8Bytes))
            {
                error = null;
                return(true);
            }

            error = TokenValidationError.MissingClaim(OAuth2Claims.AuthTime.ToString());
            return(false);
        }
Beispiel #15
0
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload is null)
            {
                error = TokenValidationError.MalformedToken();
                return(false);
            }

            if (payload.ContainsClaim(_claim))
            {
                error = null;
                return(true);
            }

            error = TokenValidationError.MissingClaim(_claim);
            return(false);
        }
Beispiel #16
0
        /// <inheritsdoc />
        private Jwk[] GetKeys(JwtHeaderDocument header, string metadataAddress)
        {
            if (_disposed)
            {
                ThrowHelper.ThrowObjectDisposedException(typeof(JwksHttpKeyProvider));
            }

            var  kid = header.Kid;
            long now = EpochTime.UtcNow;

            if (_currentJwks != null && _syncAfter > now)
            {
                return(_currentJwks.GetKeys(kid));
            }

            if (_syncAfter <= now)
            {
                _refreshLock.Wait();
                try
                {
                    var value         = _documentRetriever.GetDocument(metadataAddress, CancellationToken.None);
                    var refreshedJwks = Jwks.FromJson(Issuer, value);
                    Jwks.PublishJwksRefreshed(refreshedJwks);
                    _currentJwks = refreshedJwks;
                    _syncAfter   = now + AutomaticRefreshInterval;
                }
                catch
                {
                    _syncAfter = now + (AutomaticRefreshInterval < RefreshInterval ? AutomaticRefreshInterval : RefreshInterval);
                    throw;
                }
                finally
                {
                    _refreshLock.Release();
                }
            }

            if (_currentJwks != null)
            {
                return(_currentJwks.GetKeys(kid));
            }

            ThrowHelper.ThrowInvalidOperationException_UnableToObtainKeysException(metadataAddress);
            return(Array.Empty <Jwk>());
        }
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload is null)
            {
                error = TokenValidationError.MalformedToken();
                return(false);
            }

            if (payload.ContainsClaim(_claim))
            {
#if NET5_0_OR_GREATER
                Unsafe.SkipInit(out error);
#else
                error = default;
#endif
                return(true);
            }

            error = TokenValidationError.MissingClaim(_claim);
            return(false);
        }
Beispiel #18
0
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (header is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.header);
            }

            if (header.Alg.IsEmpty)
            {
                error = TokenValidationError.MissingHeader(JwtHeaderParameterNames.Alg.ToString());
                return(false);
            }

            if (!header.Alg.ValueEquals(_algorithm))
            {
                error = TokenValidationError.InvalidHeader(JwtHeaderParameterNames.Alg.ToString());
                return(false);
            }

            error = null;
            return(true);
        }
Beispiel #19
0
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (!payload.TryGetClaim(JwtClaimNames.Exp.EncodedUtf8Bytes, out var expires))
            {
                error = TokenValidationError.MissingClaim(JwtClaimNames.Exp.ToString());
                return(false);
            }

            if (!payload.TryGetClaim(JwtClaimNames.Jti.EncodedUtf8Bytes, out var jti))
            {
                error = TokenValidationError.MissingClaim(JwtClaimNames.Jti.ToString());
                return(false);
            }

            if (!_tokenReplayCache.TryAdd(jti.GetString(), expires.GetInt64()))
            {
                error = TokenValidationError.TokenReplayed();
                return(false);
            }

            error = null;
            return(true);
        }
Beispiel #20
0
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload is null)
            {
                error = TokenValidationError.MalformedToken();
                return(false);
            }

            if (!payload.TryGetClaim(_claim, out var claim))
            {
                error = TokenValidationError.MissingClaim(_claim);
                return(false);
            }

            if (!claim.TryGetDouble(out var value) || _value != value)
            {
                error = TokenValidationError.InvalidClaim(_claim);
                return(false);
            }

            error = null;
            return(true);
        }
        public bool TryValidate(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload is null)
            {
                error = TokenValidationError.MalformedToken();
                return(false);
            }

            if (!payload.TryGetClaim(OAuth2Claims.Acr.EncodedUtf8Bytes, out var property))
            {
                error = TokenValidationError.MissingClaim(OAuth2Claims.Acr.ToString());
                return(false);
            }

            if (!property.ValueEquals(_requiredAcr))
            {
                error = TokenValidationError.InvalidClaim(OAuth2Claims.Acr.ToString());
                return(false);
            }

            error = null;
            return(true);
        }
        /// <inheritdoc/>
        public void AddHeader(ReadOnlySpan <byte> rawHeader, JwtHeaderDocument header)
        {
            bool lockTaken = false;

            try
            {
                _spinLock.Enter(ref lockTaken);
                var node = new Node(rawHeader.ToArray(), header.Clone(), _head);
                if (_count >= MaxSize)
                {
                    RemoveLeastRecentlyUsed();
                }
                else
                {
                    _count++;
                }

                if (_head != null)
                {
                    _head.Previous = node;
                }

                _head = node;
                if (_tail is null)
                {
                    _tail = node;
                }
            }
            finally
            {
                if (lockTaken)
                {
                    _spinLock.Exit();
                }
            }
        }
 public Node(byte[] key, JwtHeaderDocument header, Node?next)
 {
     Key    = key;
     Header = header;
     Next   = next;
 }
Beispiel #24
0
 public void AddHeader(ReadOnlySpan <byte> rawHeader, JwtHeaderDocument header)
 {
 }
Beispiel #25
0
 public bool TryValidateSignature(JwtHeaderDocument header, JwtPayloadDocument payload, ReadOnlySpan <byte> contentBytes, ReadOnlySpan <byte> signatureSegment, [NotNullWhen(false)] out SignatureValidationError?error)
 {
     return(SignatureValidationPolicy.TryValidateSignature(header, payload, contentBytes, signatureSegment, out error));
 }
Beispiel #26
0
        /// <summary>Try to validate the token, according to the <paramref name="header"/> and the <paramref name="payload"/>.</summary>
        public bool TryValidateJwt(JwtHeaderDocument header, JwtPayloadDocument payload, [NotNullWhen(false)] out TokenValidationError?error)
        {
            if (payload.Control != 0)
            {
                if (RequireAudience)
                {
                    if (payload.MissingAudience)
                    {
                        error = TokenValidationError.MissingClaim(JwtClaimNames.Aud.ToString());
                        goto Error;
                    }

                    if (payload.InvalidAudience)
                    {
                        error = TokenValidationError.InvalidClaim(JwtClaimNames.Aud.ToString());
                        goto Error;
                    }
                }

                if (RequireIssuer)
                {
                    if (payload.MissingIssuer)
                    {
                        error = TokenValidationError.MissingClaim(JwtClaimNames.Iss.ToString());
                        goto Error;
                    }

                    if (payload.InvalidIssuer)
                    {
                        error = TokenValidationError.InvalidClaim(JwtClaimNames.Iss.ToString());
                        goto Error;
                    }
                }

                if (RequireExpirationTime)
                {
                    if (payload.MissingExpirationTime)
                    {
                        error = TokenValidationError.MissingClaim(JwtClaimNames.Exp.ToString());
                        goto Error;
                    }

                    if (payload.Expired)
                    {
                        error = TokenValidationError.Expired();
                        goto Error;
                    }
                }

                if (payload.NotYetValid)
                {
                    error = TokenValidationError.NotYetValid();
                    goto Error;
                }
            }

            var validators = _validators;

            for (int i = 0; i < validators.Length; i++)
            {
                if (!validators[i].TryValidate(header, payload, out error))
                {
                    goto Error;
                }
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out error);
#else
            error = default;
#endif
            return(true);

Error:
            return(false);
        }
Beispiel #27
0
 internal Jwt(JwtHeaderDocument header, JwtPayloadDocument payload)
 {
     _header  = header;
     _payload = payload;
 }
Beispiel #28
0
 private Jwt(JwtHeaderDocument header, JwtPayloadDocument payload, TokenValidationError error)
 {
     _header  = header;
     _payload = payload;
     _error   = error;
 }
Beispiel #29
0
        internal static bool TryParseHeader(ReadOnlyMemory <byte> utf8Payload, byte[]?buffer, TokenValidationPolicy policy, [NotNullWhen(true)] out JwtHeaderDocument?header, [NotNullWhen(false)] out TokenValidationError?error)
        {
            ReadOnlySpan <byte> utf8JsonSpan = utf8Payload.Span;
            var database = new JsonMetadata(utf8Payload.Length);
            int algIdx   = -1;
            int encIdx   = -1;
            int kidIdx   = -1;
            int critIdx  = -1;

            var reader = new Utf8JsonReader(utf8JsonSpan);

            if (reader.Read())
            {
                JsonTokenType tokenType = reader.TokenType;
                if (tokenType == JsonTokenType.StartObject)
                {
                    while (reader.Read())
                    {
                        tokenType = reader.TokenType;
                        int tokenStart = (int)reader.TokenStartIndex;

                        if (tokenType == JsonTokenType.EndObject)
                        {
                            break;
                        }
                        else if (tokenType != JsonTokenType.PropertyName)
                        {
                            error = TokenValidationError.MalformedToken();
                            goto Error;
                        }

                        // Adding 1 to skip the start quote will never overflow
                        Debug.Assert(tokenStart < int.MaxValue);

                        database.Append(JsonTokenType.PropertyName, tokenStart + 1, reader.ValueSpan.Length);
                        if (reader.ValueSpan.IndexOf((byte)'\\') != -1)
                        {
                            database.SetNeedUnescaping(database.Length - JsonRow.Size);
                        }

                        ReadOnlySpan <byte> memberName = reader.ValueSpan;

                        reader.Read();
                        tokenType  = reader.TokenType;
                        tokenStart = (int)reader.TokenStartIndex;

                        // Since the input payload is contained within a Span,
                        // token start index can never be larger than int.MaxValue (i.e. utf8JsonSpan.Length).
                        Debug.Assert(reader.TokenStartIndex <= int.MaxValue);
                        if (tokenType == JsonTokenType.String)
                        {
                            if (memberName.Length == 3)
                            {
                                switch ((JwtHeaderParameters)IntegerMarshal.ReadUInt24(memberName))
                                {
                                case JwtHeaderParameters.Alg:
                                    algIdx = database.Length;
                                    break;

                                case JwtHeaderParameters.Enc:
                                    encIdx = database.Length;
                                    break;

                                case JwtHeaderParameters.Kid:
                                    kidIdx = database.Length;
                                    break;
                                }
                            }

                            // Adding 1 to skip the start quote will never overflow
                            Debug.Assert(tokenStart < int.MaxValue);
                            database.Append(JsonTokenType.String, tokenStart + 1, reader.ValueSpan.Length);
                        }
                        else if (tokenType == JsonTokenType.StartObject)
                        {
                            int count    = Utf8JsonReaderHelper.SkipObject(ref reader);
                            int index    = database.Length;
                            int tokenEnd = (int)reader.TokenStartIndex;
                            database.Append(JsonTokenType.StartObject, tokenStart, tokenEnd - tokenStart + 1);
                            database.SetNumberOfRows(index, count);
                        }
                        else if (tokenType == JsonTokenType.StartArray)
                        {
                            int count;
                            if (memberName.Length == 4 &&
                                (JwtHeaderParameters)IntegerMarshal.ReadUInt32(memberName) == JwtHeaderParameters.Crit &&
                                !policy.IgnoreCriticalHeader)
                            {
                                critIdx = database.Length;
                                if (!TryCheckCrit(ref reader, out count))
                                {
                                    error = TokenValidationError.MalformedToken("The 'crit' header parameter must be an array of string.");
                                    goto Error;
                                }
                            }
                            else
                            {
                                count = Utf8JsonReaderHelper.SkipArray(ref reader);
                            }

                            int index    = database.Length;
                            int tokenEnd = (int)reader.TokenStartIndex;
                            database.Append(JsonTokenType.StartArray, tokenStart, tokenEnd - tokenStart + 1);
                            database.SetNumberOfRows(index, count);
                        }
                        else
                        {
                            Debug.Assert(tokenType >= JsonTokenType.Number && tokenType <= JsonTokenType.Null);
                            database.Append(tokenType, tokenStart, reader.ValueSpan.Length);
                        }
                    }
                }
            }

            Debug.Assert(reader.BytesConsumed == utf8JsonSpan.Length);
            database.CompleteAllocations();

            header = new JwtHeaderDocument(new JwtDocument(utf8Payload, database, buffer), algIdx, encIdx, kidIdx, critIdx);
#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out error);
#else
            error = default;
#endif
            return(true);

Error:
#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out header);
#else
            header = default;
#endif
            return(false);
        }
Beispiel #30
0
 /// <inheritsdoc />
 public Jwk[] GetKeys(JwtHeaderDocument header)
 {
     return(GetKeys(header, _jwksAddress));
 }