Esempio n. 1
0
        /// <summary>
        /// Get an access token using either the flow "JWTs as Authorization Grants" defined in RFC 7523 Section 2.1 or
        /// "Client Acting on Behalf of Itself" defined in RFC 7521 Section 6.2 with JWT client credentials signed with
        /// an algorithm appropiate for the supplied certificate.
        /// </summary>
        /// <param name="session">Ramone session.</param>
        /// <param name="key">The key used by the signing algorithm.</param>
        /// <param name="args">Assertion arguments.</param>
        /// <param name="flowType">Specify which client authentication flow to use.</param>
        /// <param name="extraHeaders">Optionally specify extra headers in the assertion.</param>
        /// <param name="extraClaims">Optionally specify extra claims in the assertion.</param>
        /// <param name="extraRequestArgs">Optionally specify extra arguments in the POST data of the HTTP request.</param>
        /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
        /// <returns></returns>
        /// <remarks>For RSA the number of signature bits are independent of the keysize, this function will always use RS256 for RSA.</remarks>
        public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT_ByCertificate(
            this ISession session,
            X509Certificate2 cert,
            AssertionArgs args,
            ClientAuthenticationFlowType flowType,
            IDictionary <string, object> extraHeaders     = null,
            IDictionary <string, object> extraClaims      = null,
            IDictionary <string, string> extraRequestArgs = null,
            bool useAccessToken = true)
        {
            if (cert == null)
            {
                throw new ArgumentNullException(nameof(cert));
            }
            if (!cert.HasPrivateKey)
            {
                throw new InvalidOperationException("The certificate does not contain a private key");
            }
            AsymmetricAlgorithm key = cert.GetRSAPrivateKey();

            if (key == null)
            {
                key = GetECDsaPublicKey.Value?.Invoke(cert);
            }
            if (key == null)
            {
                throw new NotSupportedException(string.Format("Unsupported private key: {0}", cert.PrivateKey));
            }
            return(OAuth2_GetAccessTokenFromJWT_ByKey(session, key, args, flowType, extraHeaders, extraClaims, extraRequestArgs, useAccessToken));
        }
Esempio n. 2
0
        static void AuthorizeGoogleAccess_Using_JWT()
        {
            Console.WriteLine("Loading certificate from " + JWT_CertificatePath);

            // Load certificate from file and get a crypto service provider for SHA256 signing
            X509Certificate2 certificate = new X509Certificate2(JWT_CertificatePath, "notasecret", X509KeyStorageFlags.Exportable);

            using (RSACryptoServiceProvider cp = (RSACryptoServiceProvider)certificate.PrivateKey)
            {
                // Create new crypto service provider that supports SHA256 (and don't ask me why the first one doesn't)
                CspParameters cspParam = new CspParameters
                {
                    KeyContainerName = cp.CspKeyContainerInfo.KeyContainerName,
                    KeyNumber        = cp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2
                };

                using (var aes_csp = new RSACryptoServiceProvider(cspParam)
                {
                    PersistKeyInCsp = false
                })
                {
                    // Parameters for JWT creation
                    AssertionArgs args = new AssertionArgs
                    {
                        Audience = TokenEndpointUrl,
                        Issuer   = JWT_Issuer,
                        Scope    = Scope
                    };

                    Console.WriteLine("Authorizing with Google");
                    OAuth2AccessTokenResponse token = Session.OAuth2_GetAccessTokenFromJWT_RSASHA256(aes_csp, args);
                }
            }
        }
Esempio n. 3
0
 /// <summary>
 /// Get an access token using the flow "Client Credentials Grant" with RAS-SHA256 signed JWT client credentials.
 /// </summary>
 /// <param name="session">Ramone session.</param>
 /// <param name="cp">RSA Crypto provider used to do the RSA-SHA256 signing.</param>
 /// <param name="args">Assertion arguments.</param>
 /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
 /// <returns></returns>
 public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT_RSASHA256(
     this ISession session,
     RSACryptoServiceProvider cp,
     AssertionArgs args,
     bool useAccessToken = true)
 {
     return(OAuth2_GetAccessTokenFromJWT(session, Jose.JwsAlgorithm.RS256, cp, args, useAccessToken));
 }
Esempio n. 4
0
 /// <summary>
 /// Get an access token using the flow "Client Credentials Grant" with SHA256 signed JWT client credentials.
 /// </summary>
 /// <param name="session">Ramone session.</param>
 /// <param name="shaKey">Binary representation of the SHA256 key.</param>
 /// <param name="args">Assertion arguments</param>
 /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
 /// <returns></returns>
 public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT_SHA256(
     this ISession session,
     byte[] shaKey,
     AssertionArgs args,
     bool useAccessToken = true)
 {
     return(OAuth2_GetAccessTokenFromJWT(session, Jose.JwsAlgorithm.HS256, shaKey, args, useAccessToken));
 }
Esempio n. 5
0
        /// <summary>
        /// Get an access token using either the flow "JWTs as Authorization Grants" defined in RFC 7523 Section 2.1 or
        /// "Client Acting on Behalf of Itself" defined in RFC 7521 Section 6.2 with JWT client credentials signed with
        /// an algorithm appropiate for the supplied key.
        /// </summary>
        /// <param name="session">Ramone session.</param>
        /// <param name="key">The key used by the signing algorithm.</param>
        /// <param name="args">Assertion arguments.</param>
        /// <param name="flowType">Specify which client authentication flow to use.</param>
        /// <param name="extraHeaders">Optionally specify extra headers in the assertion.</param>
        /// <param name="extraClaims">Optionally specify extra claims in the assertion.</param>
        /// <param name="extraRequestArgs">Optionally specify extra arguments in the POST data of the HTTP request.</param>
        /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
        /// <returns></returns>
        /// <remarks>For RSA the number of signature bits are independent of the keysize, this function will always use RS256 for RSA.</remarks>
        public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT_ByKey(
            this ISession session,
            object key,
            AssertionArgs args,
            ClientAuthenticationFlowType flowType,
            IDictionary <string, object> extraHeaders     = null,
            IDictionary <string, object> extraClaims      = null,
            IDictionary <string, string> extraRequestArgs = null,
            bool useAccessToken = true)
        {
            object testKey = key ?? throw new ArgumentNullException(nameof(key));

            if (testKey is CngKey cngKey)
            {
                if (cngKey.AlgorithmGroup.Equals(CngAlgorithmGroup.ECDiffieHellman) || cngKey.AlgorithmGroup.Equals(CngAlgorithmGroup.ECDsa))
                {
                    testKey = new ECDsaCng(cngKey);
                }
                else if (cngKey.AlgorithmGroup.Equals(CngAlgorithmGroup.Rsa))
                {
                    testKey = new RSACng(cngKey);
                }
                else
                {
                    throw new NotSupportedException(string.Format("Unsupported algorithm: {0}", cngKey.Algorithm));
                }
            }
            Jose.JwsAlgorithm alg;
            if (testKey is RSA)
            {
                alg = Jose.JwsAlgorithm.RS256;
            }
            else if (testKey is ECDsa ecdsaKey)
            {
                switch (ecdsaKey.KeySize)
                {
                case 256:
                    alg = Jose.JwsAlgorithm.ES256;
                    break;

                case 384:
                    alg = Jose.JwsAlgorithm.ES384;
                    break;

                case 521: // NB: ES512 uses the P-521/secp521r1 curve which has a key size of 521 bits, this is not a typo...
                    alg = Jose.JwsAlgorithm.ES512;
                    break;

                default:
                    throw new NotSupportedException(string.Format("Unsupported ECDSA key size: {0}", ecdsaKey.KeySize));
                }
            }
            else
            {
                throw new NotSupportedException(string.Format("Unsupported private key type: {0}", key.GetType()));
            }
            return(OAuth2_GetAccessTokenFromJWT(session, alg, key, args, flowType, extraHeaders, extraClaims, extraRequestArgs, useAccessToken));
        }
Esempio n. 6
0
 /// <summary>
 /// Get an access token using the flow "Client Credentials Grant" defined in RFC 6749 Section 4.4 with JWT client credentials signed with a generic algorithm.
 /// </summary>
 /// <param name="session">Ramone session.</param>
 /// <param name="signingAlgorithm">An implementation of ISigningAlgorithm to do the actual signing.</param>
 /// <param name="key">The key used by the signing algorithm.</param>
 /// <param name="args">Assertion arguments.</param>
 /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
 /// <returns></returns>
 public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT(
     this ISession session,
     Jose.JwsAlgorithm alg,
     object key,
     AssertionArgs args,
     bool useAccessToken = true)
 {
     return(OAuth2_GetAccessTokenFromJWT(session, alg, key, args, ClientAuthenticationFlowType.Rfc7523Section21, null, null, null, useAccessToken));
 }
Esempio n. 7
0
        /// <summary>
        /// Get an access token using either the flow "JWTs as Authorization Grants" defined in RFC 7523 Section 2.1 or
        /// "Client Acting on Behalf of Itself" defined in RFC 7521 Section 6.2 with JWT client credentials signed with a generic algorithm.
        /// </summary>
        /// <param name="session">Ramone session.</param>
        /// <param name="alg">An implementation of ISigningAlgorithm to do the actual signing.<</param>
        /// <param name="key">The key used by the signing algorithm.</param>
        /// <param name="args">Assertion arguments.</param>
        /// <param name="flowType">Specify which client authentication flow to use.</param>
        /// <param name="extraHeaders">Optionally specify extra headers in the assertion.</param>
        /// <param name="extraClaims">Optionally specify extra claims in the assertion.</param>
        /// <param name="extraRequestArgs">Optionally specify extra arguments in the POST data of the HTTP request.</param>
        /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
        /// <returns></returns>
        public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT(
            this ISession session,
            Jose.JwsAlgorithm alg,
            object key,
            AssertionArgs args,
            ClientAuthenticationFlowType flowType,
            IDictionary <string, object> extraHeaders     = null,
            IDictionary <string, object> extraClaims      = null,
            IDictionary <string, string> extraRequestArgs = null,
            bool useAccessToken = true)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }
            if (flowType != ClientAuthenticationFlowType.Rfc7523Section21 && flowType != ClientAuthenticationFlowType.Rfc7521Section62)
            {
                throw new ArgumentOutOfRangeException(nameof(flowType));
            }

            OAuth2Settings settings = GetSettings(session);

            DateTime now          = DateTime.UtcNow;
            DateTime issuedAtDate = now.Add(args.IssueTimeOffset);
            DateTime expiresDate  = issuedAtDate.Add(args.ExpireTime);
            long     issuedAt     = issuedAtDate.ToUnixTime();
            long     expires      = expiresDate.ToUnixTime();

            IEnumerable <KeyValuePair <string, object> > baseClaims = new Dictionary <string, object>()
            {
                { "iss", args.Issuer },
                { "scope", args.Scope },
                { "aud", args.Audience },
                { "sub", args.Subject },
                { "exp", expires },
                { "iat", issuedAt }
            };

            if (extraClaims != null)
            {
                baseClaims = baseClaims.Concat(extraClaims);
            }
            var claims = baseClaims.Where(kv => kv.Value != null).ToDictionary(kv => kv.Key, kv => kv.Value);

            string token = Jose.JWT.Encode(claims, key, alg, extraHeaders: extraHeaders);

            NameValueCollection tokenRequestArgs = new NameValueCollection();

            if (flowType == ClientAuthenticationFlowType.Rfc7523Section21)
            {
                tokenRequestArgs["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
                tokenRequestArgs["assertion"]  = token;
            }
            else
            {
                tokenRequestArgs["scope"]                 = args.Scope; // This is nominally optional and redundant, but Microsoft wants it...
                tokenRequestArgs["grant_type"]            = "client_credentials";
                tokenRequestArgs["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
                tokenRequestArgs["client_assertion"]      = token;
            }
            if (extraRequestArgs != null)
            {
                foreach (var kv in extraRequestArgs)
                {
                    tokenRequestArgs[kv.Key] = kv.Value;
                }
            }

            return(GetAndStoreAccessToken(session, tokenRequestArgs, useAccessToken));
        }
Esempio n. 8
0
        /// <summary>
        /// Get an access token using the flow "Client Credentials Grant" with JWT client credentials signed with a generic algorithm.
        /// </summary>
        /// <param name="session">Ramone session.</param>
        /// <param name="signingAlgorithm">An implementation of ISigningAlgorithm to do the actual signing.</param>
        /// <param name="args">Assertion arguments.</param>
        /// <param name="useAccessToken">Store the returned access token in session and use that in future requests to the resource server.</param>
        /// <returns></returns>
        public static OAuth2AccessTokenResponse OAuth2_GetAccessTokenFromJWT(this ISession session, Jose.JwsAlgorithm alg, object key, AssertionArgs args, bool useAccessToken = true)
        {
            OAuth2Settings settings = GetSettings(session);

            DateTime now          = DateTime.UtcNow;
            DateTime issuedAtDate = now.Add(args.IssueTimeOffset);
            DateTime expiresDate  = issuedAtDate.Add(args.ExpireTime);
            long     issuedAt     = issuedAtDate.ToUnixTime();
            long     expires      = expiresDate.ToUnixTime();

            var claims = new Dictionary <string, object>()
            {
                { "iss", args.Issuer },
                { "scope", args.Scope },
                { "aud", args.Audience },
                { "sub", args.Subject },
                { "exp", expires },
                { "iat", issuedAt }
            };

            claims = claims.Where(kv => kv.Value != null).ToDictionary(kv => kv.Key, kv => kv.Value);

            string token = Jose.JWT.Encode(claims, key, alg);

            NameValueCollection tokenRequestArgs = new NameValueCollection();

            tokenRequestArgs["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
            tokenRequestArgs["assertion"]  = token;

            return(GetAndStoreAccessToken(session, tokenRequestArgs, useAccessToken));
        }