Beispiel #1
0
        /// <summary>Publish an event that notify a <see cref="Jwks"/> has been refreshed.</summary>
        public static void PublishJwksRefreshed(Jwks oldJwks, Jwks newJwks)
        {
            if (OnJwksRefreshed != null)
            {
                var added   = new Jwks(newJwks.Issuer);
                var removed = new Jwks(newJwks.Issuer);
                for (int i = 0; i < oldJwks.Count; i++)
                {
                    var key = oldJwks._keys[i];
                    if (!newJwks.Contains(key))
                    {
                        removed._keys.Add(key);
                    }
                }

                for (int i = 0; i < newJwks.Count; i++)
                {
                    var key = newJwks._keys[i];
                    if (!oldJwks.Contains(key))
                    {
                        added._keys.Add(key);
                    }
                }

                if (added.Count != 0 || removed.Count != 0)
                {
                    OnJwksRefreshed(added, removed);
                }
            }
        }
        /// <inheritdoc/>
        protected override Jwks GetKeysFromSource()
        {
            using var retriever = _documentRetrieverFactory();
            var value = retriever.GetDocument(_jwksAddress, CancellationToken.None);

            return(Jwks.FromJson(Issuer, value));
        }
Beispiel #3
0
        /// <summary>Returns a new instance of <see cref="Jwks"/>.</summary>
        /// <param name="issuer">The issuer of the keys.</param>
        /// <param name="json">a string that contains JSON Web Key parameters in JSON format.</param>
        public static Jwks FromJson(string issuer, ReadOnlySpan <byte> json)
        {
            // a JWKS is :
            // {
            //   "keys": [
            //   { jwk1 },
            //   { jwk2 },
            //   ...
            //   ]
            // }
            var jwks   = new Jwks(issuer);
            var reader = new Utf8JsonReader(json, true, default);

            if (reader.Read() && reader.TokenType is JsonTokenType.StartObject && reader.Read())
            {
                while (reader.TokenType is JsonTokenType.PropertyName)
                {
                    var propertyName = reader.ValueSpan;
                    if (propertyName.Length == 4)
                    {
                        ref byte propertyNameRef = ref MemoryMarshal.GetReference(propertyName);
                        if (IntegerMarshal.ReadUInt32(ref propertyNameRef) == keys /* keys */)
                        {
                            if (reader.Read() && reader.TokenType is JsonTokenType.StartArray)
                            {
                                while (reader.Read() && reader.TokenType is JsonTokenType.StartObject)
                                {
                                    Jwk jwk = Jwk.FromJsonReader(ref reader);
                                    jwks.Add(jwk);
                                }

                                if (!(reader.TokenType is JsonTokenType.EndArray) || !reader.Read())
                                {
                                    ThrowHelper.ThrowInvalidOperationException_MalformedJwks();
                                }
                            }

                            continue;
                        }
                    }

                    reader.Read();
                    if (reader.TokenType >= JsonTokenType.String && reader.TokenType <= JsonTokenType.Null)
                    {
                        reader.Read();
                    }
                    else if (reader.TokenType == JsonTokenType.StartObject)
                    {
                        JsonParser.ConsumeJsonObject(ref reader);
                    }
                    else if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        JsonParser.ConsumeJsonArray(ref reader);
                    }
                    else
                    {
                        ThrowHelper.ThrowInvalidOperationException_MalformedJwks();
                    }
                }
            }
        /// <summary>Configure the signature behavior for a specific <paramref name="issuer"/>.</summary>
        public TokenValidationPolicyBuilder RequireSignature(string issuer, Jwks keys, SignatureAlgorithm defaultAlgorithm)
        {
            if (keys is null)
            {
                throw new ArgumentNullException(nameof(keys));
            }

            return(RequireSignatureByDefault(issuer, new StaticKeyProvider(keys), defaultAlgorithm));
        }
Beispiel #5
0
        /// <summary>
        /// Initializes a new instance of <see cref="StaticKeyProvider"/>.
        /// </summary>
        /// <param name="jwks"></param>
        public StaticKeyProvider(Jwks jwks)
        {
            if (jwks is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.jwks);
            }

            _jwks = jwks;
        }
Beispiel #6
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 #7
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>());
        }
Beispiel #8
0
        /// <inheritsdoc />
        protected Jwk[] GetKeys(JwtHeader header, string metadataAddress)
        {
            if (_disposed)
            {
                ThrowHelper.ThrowObjectDisposedException(GetType());
            }

            var kid = header.Kid;
            var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

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

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

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

            ThrowHelper.ThrowInvalidOperationException_UnableToObtainKeysException(metadataAddress);
            return(Array.Empty <Jwk>());
        }
Beispiel #9
0
        /// <summary>
        /// Returns a new instance of <see cref="Jwks"/>.
        /// </summary>
        /// <param name="json">a string that contains JSON Web Key parameters in JSON format.</param>
        /// <returns><see cref="Jwks"/></returns>
        public static Jwks FromJson(ReadOnlySpan <byte> json)
        {
            // a JWKS is :
            // {
            //   "keys": [
            //   { jwk1 },
            //   { jwk2 },
            //   ...
            //   ]
            // }
            var jwks   = new Jwks();
            var reader = new Utf8JsonReader(json, true, default);

            if (reader.Read() &&
                reader.TokenType is JsonTokenType.StartObject &&
                reader.Read() &&
                reader.TokenType is JsonTokenType.PropertyName)
            {
                var propertyName = reader.ValueSpan /* reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan */;
                if (propertyName.Length == 4)
                {
                    ref byte propertyNameRef = ref MemoryMarshal.GetReference(propertyName);
                    if (IntegerMarshal.ReadUInt32(ref propertyNameRef) == keys /* keys */)
                    {
                        if (reader.Read() && reader.TokenType is JsonTokenType.StartArray)
                        {
                            while (reader.Read() && reader.TokenType is JsonTokenType.StartObject)
                            {
                                Jwk jwk = Jwk.FromJsonReader(ref reader);
                                jwks.Add(jwk);
                            }

                            if (!(reader.TokenType is JsonTokenType.EndArray) || !reader.Read())
                            {
                                ThrowHelper.ThrowInvalidOperationException_MalformedJwks();
                            }
                        }
                    }
                }
            }
Beispiel #10
0
 public JwtReader(Jwks encryptionKeys)
 => throw new NotImplementedException();
 public TokenValidationPolicyBuilder RequireSignature(Jwks keySet, SignatureAlgorithm?algorithm)
 => throw new NotSupportedException();
Beispiel #12
0
 /// <summary>Publish an event that notify a <see cref="Jwks"/> has been refreshed.</summary>
 public static void PublishJwksRefreshed(Jwks keys)
 => OnJwksRefreshed?.Invoke(keys);
Beispiel #13
0
 /// <inheritsdoc />
 protected override Jwks DeserializeKeySet(string value)
 {
     return(Jwks.FromJson(value));
 }
Beispiel #14
0
 /// <summary>Initializes a new instance of <see cref="CachedKeyProvider"/> class.</summary>
 protected CachedKeyProvider(long minimumRefreshInterval = DefaultMinimumRefreshInterval, long automaticRefreshInterval = DefaultAutomaticRefreshInterval)
 {
     _currentJwks             = EmptyJwks;
     MinimumRefreshInterval   = minimumRefreshInterval;
     AutomaticRefreshInterval = automaticRefreshInterval;
 }
 /// <summary>Defines the <see cref="Jwks"/> used to decrypt the tokens.</summary>
 public TokenValidationPolicyBuilder WithDecryptionKeys(Jwks decryptionKeys)
 => WithDecryptionKeys(new StaticKeyProvider(decryptionKeys));
 /// <summary>
 /// Defines the default signature validation when there is no issuer configuration.
 /// Use the method <see cref="RequireSignatureByDefault(string, IKeyProvider, SignatureAlgorithm?)"/> for linking the issuer with the signature.
 /// </summary>
 public TokenValidationPolicyBuilder RequireSignatureByDefault(Jwks keySet, SignatureAlgorithm?algorithm)
 => RequireSignatureByDefault(new StaticKeyProvider(keySet), algorithm);
 /// <summary>
 /// Defines the default signature validation when there is no issuer configuration.
 /// Use the method <see cref="RequireSignatureByDefault(string, IKeyProvider, SignatureAlgorithm?)"/> for linking the issuer with the signature.
 /// </summary>
 public TokenValidationPolicyBuilder RequireSignatureByDefault(Jwks keySet)
 => RequireSignatureByDefault(keySet, null);