Ejemplo n.º 1
0
        public void DecodeToken_WithoutToken_Should_Throw_Exception()
        {
            var builder = new JwtBuilder();

            Action decodingANullJwt = ()
                                      => builder.Decode(null);

            decodingANullJwt.Should()
            .Throw <ArgumentException>("because null is not a valid value for a token");
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Validate JWT signature.
        /// This JWT is signed with a MessageBird account unique secret key, ensuring the request is from MessageBird and a specific account.
        /// The JWT contains the following claims:
        /// <list type="bullet">
        ///     <item>
        ///         <term>url_hash</term>
        ///         <description>the raw URL hashed with SHA256 ensuring the URL wasn't altered.</description>
        ///     </item>
        ///     <item>
        ///         <term>payload_hash</term>
        ///         <description>the raw payload hashed with SHA256 ensuring the payload wasn't altered.</description>
        ///     </item>
        ///     <item>
        ///         <term>jti</term>
        ///         <description>a unique token ID to implement an optional non-replay check (NOT validated by default).</description>
        ///     </item>
        ///     <item>
        ///         <term>nbf</term>
        ///         <description>the not before timestamp.</description>
        ///     </item>
        ///     <item>
        ///         <term>exp</term>
        ///         <description>the expiration timestamp is ensuring that a request isn't captured and used at a later time.</description>
        ///     </item>
        ///     <item>
        ///         <term>iss</term>
        ///         <description>the issuer name, always MessageBird.</description>
        ///     </item>
        /// </list>
        /// </summary>
        ///
        /// <param name="signature">request signature taken from request header MessageBird-Signature-JWT.</param>
        /// <param name="url">full URL of the receiving endpoint, including scheme, host, path and query.</param>
        /// <param name="body">request body.</param>
        /// <returns>A dictionary representing decoded JWT signature token claims</returns>
        /// <exception cref="RequestValidationException">Throws if signature can not be verified.</exception>
        public IDictionary <string, string> ValidateSignature(string signature, string url, byte[] body)
        {
            IDictionary <string, string> payload;

            try
            {
                payload = _jwtBuilder.Decode <IDictionary <string, string> >(signature);
            }
            catch (Exception e)
            {
                throw new RequestValidationException(e.Message, e);
            }

            string[] requiredClaims = { "iss", "nbf", "exp" };
            foreach (string claim in requiredClaims)
            {
                if (payload.ContainsKey(claim))
                {
                    continue;
                }
                throw new RequestValidationException(String.Format("invalid jwt: claim {0} is missing", claim));
            }

            if (!payload["iss"].Equals(TokenIssuer))
            {
                throw new RequestValidationException("invalid jwt: claim iss has wrong value");
            }

            if (!_skipURLValidation)
            {
                string expectedURLHash = GetSHA256Hash(Encoding.ASCII.GetBytes(url));
                if (!payload["url_hash"].Equals(expectedURLHash))
                {
                    throw new RequestValidationException("invalid jwt: claim url_hash is invalid");
                }
            }

            bool bodyExist        = body != null && body.Length > 0;
            bool payloadHashExist = payload.ContainsKey("payload_hash");

            if (!bodyExist && payloadHashExist)
            {
                throw new RequestValidationException("invalid jwt: claim payload_hash is set but actual payload is missing");
            }
            if (bodyExist && !payloadHashExist)
            {
                throw new RequestValidationException("invalid jwt: claim payload_hash is not set but payload is present");
            }
            if (bodyExist && !payload["payload_hash"].Equals(GetSHA256Hash(body)))
            {
                throw new RequestValidationException("invalid jwt: claim payload_hash is invalid");
            }

            return(payload);
        }
Ejemplo n.º 3
0
        void DecodingWithBuilder_FPs(bool condition)
        {
            var builder1 = new JwtBuilder();

            Init();
            builder1.Decode(invalidToken); // Noncompliant FP, initialization in local function is not tracked

            void Init()
            {
                builder1 = builder1.WithSecret(secret).MustVerifySignature();
            }
        }
Ejemplo n.º 4
0
        public static T Decode <T>(string jsonObject)
        {
            var builder = new JwtBuilder();

            builder.WithAlgorithm(new HMACSHA256Algorithm());
            builder.WithSecret(Environment.GetEnvironmentVariable("secret"));
            builder.WithVerifySignature(true);

            T decodedDto = builder.Decode <T>(jsonObject);

            return(decodedDto);
        }
Ejemplo n.º 5
0
        void DecodingWithBuilder_FNs(bool condition)
        {
            var builder1 = new JwtBuilder();

            if (condition)
            {
                builder1 = builder1.WithSecret(secret);
            }
            builder1.Decode(invalidToken);             // FN, this is not SE rule, only linear initialization is considered

            CreateBuilder().Decode(invalidToken);      // FN, cross procedural initialization is not tracked
            CreateLocalBuilder().Decode(invalidToken); // FN, local function initialization is not tracked

            JwtBuilder CreateLocalBuilder() => new JwtBuilder().DoNotVerifySignature();
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Attempts to decrypt and deserialize the given encoded string into an object of type T.
        /// </summary>
        /// <param name="encodedString"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns>On success, returns instance of T. On failure, returns default.</returns>
        public T Decode <T>(string encodedString) where T : IIdentityProvider
        {
            JwtBuilder builder = CreateJwtBuilder().MustVerifySignature();

            try
            {
                T obj = builder.Decode <T>(encodedString);
                if (obj.GetExpirationTicks() < DateTime.Now.Ticks)
                {
                    throw new JwtExpiredException();
                }
                return(obj);
            }
            catch (SignatureVerificationException)
            {
                return(default);
Ejemplo n.º 7
0
        void DecodingWithBuilder_FNs(bool condition)
        {
            var builder1 = new JwtBuilder();

            if (condition)
            {
                builder1 = builder1.WithSecret(secret);
            }
            builder1.Decode(invalidToken);              //FP

            CreateBuilder("abc").Decode(invalidToken);  //FP
            CreateBuilder1("abc").Decode(invalidToken); //FP
            CreateLocalBuilder().Decode(invalidToken);

            JwtBuilder CreateLocalBuilder() => new JwtBuilder().DoNotVerifySignature();
        }
Ejemplo n.º 8
0
        void DecodingWithBuilder()
        {
            var decoded1 = new JwtBuilder() // Noncompliant {{Use only strong cipher algorithms when verifying the signature of this JWT.}}
                           .WithSecret(secret)
                           .Decode(invalidToken);

            var decoded2 = new JwtBuilder()
                           .WithSecret(secret)
                           .MustVerifySignature()
                           .Decode(invalidToken);

            var builder1 = new JwtBuilder().WithSecret(secret);

            builder1.Decode(invalidToken); // Noncompliant

            try
            {
                if (true)
                {
                    builder1.Decode(invalidToken); // Noncompliant, tracking outside nested block
                }
            }
            finally
            {
            }

            var builder2 = builder1.MustVerifySignature();

            builder2.Decode(invalidToken);

            var builder3 = new JwtBuilder().WithSecret(secret).MustVerifySignature();

            builder3.Decode(invalidToken);

            var builder4 = (((new JwtBuilder()).WithSecret(secret)));

            builder4.Decode(invalidToken); // Noncompliant

            var builder5 = new JwtBuilder().WithSecret(secret).DoNotVerifySignature();

            builder5.Decode(invalidToken);   // Noncompliant

            var decoded11 = new JwtBuilder() // Noncompliant
                            .WithSecret(secret)
                            .WithVerifySignature(true)
                            .MustVerifySignature()
                            .DoNotVerifySignature()
                            .Decode(invalidToken);

            var Decoded12 = new JwtBuilder()
                            .WithSecret(secret)
                            .WithVerifySignature(false)
                            .DoNotVerifySignature()
                            .MustVerifySignature()
                            .Decode(invalidToken);

            var Decoded21 = new JwtBuilder()
                            .WithSecret(secret)
                            .DoNotVerifySignature()
                            .WithVerifySignature(false)
                            .WithVerifySignature(true)
                            .Decode(invalidToken);

            var Decoded31 = new JwtBuilder()  // Noncompliant
                            .WithSecret(secret)
                            .MustVerifySignature()
                            .WithVerifySignature(true)
                            .WithVerifySignature(false)
                            .Decode(invalidToken);
        }
 public IDictionary <string, object> DecodeJwt(string token)
 {
     return(_builder.Decode <IDictionary <string, object> >(token));
 }
Ejemplo n.º 10
0
        /// <summary>
        /// The method checks whether the requested operation (i.e. the combination of URL and <see cref="HttpMethod"/>) is protected by one or multiple predefined scopes. Scopes can be defined statically, by applying <see cref="AuthorizationScope"/> attribute
        /// to the C# method representing a resource or a RESTful operation or dynamically during runtime by using <see cref="DynamicAuthorizationScope"/>s (see <see cref="OAuth2.DynamicScopes"/>). If at least one <see cref="DynamicAuthorizationScope"/>
        /// is defined for the corresponding method, then all predefined <see cref="AuthorizationScope"/>s are ignored. If there are no scopes defined (dynamically as well as statically), this method grants access even without an access token.
        /// In case that the resource/operation is protected by scopes, the method checks whether the request contains a valid access token in the Authorization header. Since this framework uses Self-Encoded Access Tokens, the scopes the client is granted to can be decoded from the provided access token and
        /// compared with the predefined scopes of the method. At least one granted scope must match the list of predefined scopes, otherwise the request is rejected with an <see cref="HttpStatus.Unauthorized"/> immediately (same applies if no access token is included or if the access token is invalid).
        /// </summary>
        /// <param name="context">Routed Context</param>
        public override void Manipulate(RoutedContext context)
        {
            //step 1: check whether method has scopes (i.e. is a protected resource)
            IList <string> scopes = new List <string>();

            //check first, whether there are dynamic scopes specifiec
            foreach (DynamicAuthorizationScope das in _reference.DynamicScopes)
            {
                if (das.Path.CompareTo(context.RoutingEntry.Path) == 0)
                {
                    scopes.Add(das.Scope);
                }
            }



            //if not, check whether there are static scopes via attributes defined
            if (scopes.Count == 0)
            {
                scopes = GetScopesOfMethod(context.RoutingEntry.MethodInfo);
            }

            //if there are no scopes, ...
            if (scopes.Count == 0)
            {
                //...do nothing (i.e. the request can be processed as no permission is required for accessing the resource)
                return;
            }

            //step 1a: load access token
            string token = context.Context.Request.Headers.Get("Authorization");

            if (String.IsNullOrWhiteSpace(token))
            {
                throw new HttpRequestException("Missing access token", MimeType.TEXT_PLAN)
                      {
                          Status = HttpStatus.Unauthorized
                      };
            }
            token = token.Replace("bearer ", "").Replace("Bearer ", "");

            //step 2: decode token
            string scope = null;

            try
            {
                IDictionary <string, object> payload = _decoder.Decode <IDictionary <string, object> >(token);
                if (payload.ContainsKey("scope"))
                {
                    scope = (string)payload["scope"];
                }
                else
                {
                    throw new HttpRequestException("Invalid access token", MimeType.TEXT_PLAN)
                          {
                              Status = HttpStatus.Unauthorized
                          };
                }
            }
            catch (TokenExpiredException)
            {
                throw new HttpRequestException("Token has expired", MimeType.TEXT_PLAN)
                      {
                          Status = HttpStatus.Unauthorized
                      };
            }
            catch (SignatureVerificationException)
            {
                throw new HttpRequestException("Invalid access token", MimeType.TEXT_PLAN)
                      {
                          Status = HttpStatus.Unauthorized
                      };
            }
            catch (Exception)
            {
                throw new HttpRequestException("Invalid access token", MimeType.TEXT_PLAN)
                      {
                          Status = HttpStatus.Unauthorized
                      };
            }


            //step 3: check scope
            if (String.IsNullOrWhiteSpace(scope))
            {
                throw new HttpRequestException("Invalid scope: you are not allowed to access this resource", MimeType.TEXT_PLAN)
                      {
                          Status = HttpStatus.Forbidden
                      };
            }

            bool match = false;

            string[] scopess = scope.Split(' ');
            foreach (string scp in scopess)     //for all scopes supported by the access token
            {
                foreach (string scpp in scopes) //for all scopes supported by the method
                {
                    if (scp.CompareTo(scpp) == 0)
                    {
                        match = true;
                    }
                }
            }
            if (!match)
            {
                throw new HttpRequestException("Invalid scope: you are not allowed to access this resource", MimeType.TEXT_PLAN)
                      {
                          Status = HttpStatus.Forbidden
                      };
            }
        }