public async Task RetrieveToken_IsInCache_ReturnedFromCache()
        {
            var accessToken = "token1";
            var token       = new OioIdwsToken
            {
                CertificateThumbprint = "cert1",
                ExpiresUtc            = DateTimeOffset.UtcNow.AddHours(1),
            };

            var cacheMock = new Mock <ITokenCache>();

            cacheMock
            .Setup(x => x.RetrieveAsync(accessToken))
            .ReturnsAsync(token);

            Func <HttpClient> clientFactory = () => new HttpClient();
            var sut = new RestTokenProvider(clientFactory, cacheMock.Object);

            sut.Initialize(null, null, new Mock <ILogger>().Object);
            var tokenResult = await sut.RetrieveTokenAsync(accessToken);

            Assert.IsTrue(tokenResult.Success);
            Assert.AreEqual(token.CertificateThumbprint, tokenResult.Result.CertificateThumbprint);
            cacheMock.Verify(x => x.RetrieveAsync(accessToken));
        }
Ejemplo n.º 2
0
        public virtual Task <ClaimsIdentity> BuildIdentityAsync(OioIdwsToken token)
        {
            if (token == null)
            {
                throw new ArgumentNullException(nameof(token));
            }

            return(Task.FromResult(
                       new ClaimsIdentity(
                           token.Claims.Select(c => new Claim(c.Type, c.Value, c.ValueType, c.Issuer)).ToList(),
                           "OioIdws")));
        }
Ejemplo n.º 3
0
        public Task StoreAsync(string accessToken, OioIdwsToken token)
        {
            if (accessToken == null)
            {
                throw new ArgumentNullException(nameof(accessToken));
            }
            if (token == null)
            {
                throw new ArgumentNullException(nameof(token));
            }

            _cache.TryAdd(accessToken, token);
            return(Task.FromResult(0));
        }
Ejemplo n.º 4
0
        public async Task BuildFromSamlToken()
        {
            var token = new OioIdwsToken
            {
                Type   = AccessTokenType.Bearer,
                Claims = new[]
                {
                    new OioIdwsClaim
                    {
                        Type  = "nametype1",
                        Value = "name1",
                    },
                    new OioIdwsClaim
                    {
                        Type  = "roletype1",
                        Value = "role1",
                    },
                    new OioIdwsClaim
                    {
                        Type      = "type1",
                        Value     = "value1",
                        ValueType = "valutype1",
                        Issuer    = "issuer1",
                    },
                    new OioIdwsClaim
                    {
                        Type      = "type2",
                        Value     = "value2",
                        ValueType = "valutype2",
                        Issuer    = "issuer2",
                    }
                },
            };

            var sut      = new IdentityBuilder();
            var identity = await sut.BuildIdentityAsync(token);

            Assert.IsNotNull(identity);
            Assert.IsTrue(identity.IsAuthenticated);

            Assert.AreEqual("OioIdws", identity.AuthenticationType);
            Assert.IsTrue(identity.HasClaim("nametype1", "name1"));
            Assert.AreEqual(4, identity.Claims.Count());
        }
        public async Task RetrieveToken_IsInCacheButExpired_ReturnedFromRestInvocation()
        {
            var accessToken  = "token1";
            var expiredToken = new OioIdwsToken
            {
                CertificateThumbprint = "cert1",
                ExpiresUtc            = DateTimeOffset.UtcNow.AddHours(-1),
            };

            var validToken = new OioIdwsToken
            {
                CertificateThumbprint = "cert2",
                ExpiresUtc            = DateTimeOffset.UtcNow.AddHours(1),
            };

            var cacheMock = new Mock <ITokenCache>();

            cacheMock
            .Setup(x => x.RetrieveAsync(accessToken))
            .ReturnsAsync(expiredToken);

            var handler = new TokenHandler(validToken);

            Func <HttpClient> clientFactory = () => new HttpClient(handler)
            {
                BaseAddress = new Uri("http://dummy")
            };

            var sut = new RestTokenProvider(clientFactory, cacheMock.Object);

            sut.Initialize(null, null, new Mock <ILogger>().Object);
            var tokenResult = await sut.RetrieveTokenAsync(accessToken);

            Assert.IsTrue(tokenResult.Success);
            Assert.AreEqual(validToken.CertificateThumbprint, tokenResult.Result.CertificateThumbprint);
            cacheMock.Verify(x => x.RetrieveAsync(accessToken));
        }
 public TokenHandler(OioIdwsToken token)
 {
     _token = token;
 }
Ejemplo n.º 7
0
 public RetrieveTokenResult(OioIdwsToken result)
 {
     Result = result;
 }
Ejemplo n.º 8
0
        public async Task IssueAsync(OioIdwsMatchEndpointContext context)
        {
            if (string.IsNullOrEmpty(context.Request.ContentType))
            {
                SetInvalidRequest(context, "No content type was specified");
                return;
            }

            var ct = new System.Net.Mime.ContentType(context.Request.ContentType);

            var validContentType = "application/x-www-form-urlencoded";

            if (!ct.MediaType.Equals(validContentType, StringComparison.InvariantCultureIgnoreCase))
            {
                SetInvalidRequest(context, $"Content type '{validContentType}' is required.");
                return;
            }

            var form = await context.Request.ReadFormAsync();

            var tokenValueBase64 = form["saml-token"];

            if (string.IsNullOrEmpty(tokenValueBase64))
            {
                SetInvalidRequest(context, "saml-token was missing");
                return;
            }

            string tokenValue;

            try
            {
                var bytes = Convert.FromBase64String(tokenValueBase64);
                using (var stream = new MemoryStream(bytes))
                {
                    using (var reader = new StreamReader(stream))
                    {
                        tokenValue = await reader.ReadToEndAsync();
                    }
                }
            }
            catch (Exception)
            {
                SetInvalidRequest(context, "saml-token must be in base64");
                return;
            }

            var clientCertificate = context.ClientCertificate();

            _logger.WriteEntry(Log.StartingTokenValidation());
            var samlTokenValidation = await _tokenValidator.ValidateTokenAsync(tokenValue, clientCertificate, context.Options);

            if (!samlTokenValidation.Success)
            {
                _logger.WriteEntry(Log.IssuingTokenDenied(samlTokenValidation.ErrorDescription, samlTokenValidation.ValidationException));

                // Scheme is mandatory and Holder-Of-Key is currently the only supportede scheme at NemLog-in STS. Hence, we specify Holder-Of-Key.
                context.Response.SetAuthenticationFailed(AccessTokenType.HolderOfKey, AuthenticationErrorCodes.InvalidToken, samlTokenValidation.ErrorDescription);
                context.RequestCompleted();
                return;
            }

            _logger.WriteEntry(Log.TokenValidationCompleted());

            var expiresIn = context.Options.AccessTokenExpiration;

            int requestedExpiration;

            if (int.TryParse(form["should-expire-in"], out requestedExpiration))
            {
                var tmp = TimeSpan.FromSeconds(requestedExpiration);

                if (tmp < expiresIn)
                {
                    //if the client wants a lower expiration, that's ok. Never to increase it.
                    expiresIn = tmp;
                }
            }

            var storedToken = new OioIdwsToken
            {
                CertificateThumbprint = samlTokenValidation.AccessTokenType == AccessTokenType.HolderOfKey
                    ? clientCertificate?.Thumbprint?.ToLowerInvariant()
                    : null,
                Type       = samlTokenValidation.AccessTokenType,
                ExpiresUtc = context.Options.SystemClock.UtcNow + expiresIn,
                Claims     = samlTokenValidation.ClaimsIdentity.Claims.Select(x => new OioIdwsClaim
                {
                    Type      = x.Type,
                    Value     = x.Value,
                    Issuer    = x.Issuer,
                    ValueType = x.ValueType
                }).ToList(),
            };

            var accessToken = await GenerateAccessTokenAsync(context, storedToken);

            await WriteAccessTokenAsync(context.Response, accessToken, samlTokenValidation.AccessTokenType, expiresIn);

            _logger.WriteEntry(Log.TokenIssuedWithExpiration(accessToken, expiresIn));

            context.RequestCompleted();
        }
Ejemplo n.º 9
0
        private async Task <string> GenerateAccessTokenAsync(OioIdwsMatchEndpointContext context, OioIdwsToken storedToken)
        {
            var uniqueKey = _keyGenerator.GenerateUniqueKey();

            _logger.WriteEntry(Log.NewUniqueKeyGenerated(uniqueKey));

            await _securityTokenStore.StoreTokenAsync(uniqueKey, storedToken);

            _logger.WriteVerbose("Token information was committed to the Token Store");

            //store the Expiry time directly in the protected access token, allowing the Authorization Server to quickly validate the token when asked to retrieve information
            var properties = new AuthenticationProperties
            {
                ExpiresUtc = storedToken.ExpiresUtc
            };

            properties.Value(uniqueKey);

            var accessToken = context.Options.TokenDataFormat.Protect(properties);

            return(accessToken);
        }
        public async Task RetrieveAccessToken_Success_TokenInformationIsInResponse()
        {
            var wspCertificate = CertificateUtil.GetCertificate("d9f10c97aa647727adb64a349bb037c5c23c9a7a");

            var accessToken     = "dummy";
            var oioIdwsTokenKey = "accesstoken1";
            var token           = new OioIdwsToken
            {
                Type       = AccessTokenType.Bearer,
                ExpiresUtc = DateTime.UtcNow.AddHours(1),
                Claims     = new[]
                {
                    new OioIdwsClaim
                    {
                        Type      = "type1",
                        Value     = "value1",
                        ValueType = "valuetype1",
                        Issuer    = "issuer1",
                    },
                    new OioIdwsClaim
                    {
                        Type      = "type2",
                        Value     = "value2",
                        ValueType = "valuetype2",
                        Issuer    = "issuer2",
                    },
                }
            };

            var tokenStoreMock = new Mock <ISecurityTokenStore>();

            tokenStoreMock
            .Setup(x => x.RetrieveTokenAsync(oioIdwsTokenKey))
            .ReturnsAsync(token);

            var tokenDataFormatMock = new Mock <ISecureDataFormat <AuthenticationProperties> >();

            tokenDataFormatMock
            .Setup(x => x.Unprotect(accessToken))
            .Returns(new AuthenticationProperties
            {
                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(1),
                Dictionary = { { "value", oioIdwsTokenKey } }
            });

            var options = new OioIdwsAuthorizationServiceOptions
            {
                AccessTokenIssuerPath            = new PathString("/accesstoken/issue"),
                AccessTokenRetrievalPath         = new PathString("/accesstoken"),
                IssuerAudiences                  = () => Task.FromResult(new IssuerAudiences[0]),
                SecurityTokenStore               = tokenStoreMock.Object,
                TokenDataFormat                  = tokenDataFormatMock.Object,
                TrustedWspCertificateThumbprints = new[] { "d9f10c97aa647727adb64a349bb037c5c23c9a7a" },
                CertificateValidator             = X509CertificateValidator.None //no reason for tests to validate certs
            };

            using (var server = TestServerWithClientCertificate.Create(() => wspCertificate, app =>
            {
                app.UseOioIdwsAuthorizationService(options);
            }))
            {
                server.BaseAddress = new Uri("https://localhost/");

                var response = await server.HttpClient.GetAsync($"/accesstoken?{accessToken}");

                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
                Assert.AreEqual("application/json", response.Content.Headers.ContentType.MediaType);
                var responseToken = JsonConvert.DeserializeObject <OioIdwsToken>(await response.Content.ReadAsStringAsync());

                Assert.AreEqual(token.Type, responseToken.Type);
                Assert.AreEqual(token.ExpiresUtc, responseToken.ExpiresUtc);
                Assert.AreEqual(token.Claims.Count, responseToken.Claims.Count);
                Assert.AreEqual(token.Claims.ElementAt(0).Type, responseToken.Claims.ElementAt(0).Type);
                Assert.AreEqual(token.Claims.ElementAt(0).Value, responseToken.Claims.ElementAt(0).Value);
            }
        }
        public async Task RetrieveAccessToken_ExpiredAccessToken_ReturnsUnauthorized()
        {
            var wspCertificate = CertificateUtil.GetCertificate("d9f10c97aa647727adb64a349bb037c5c23c9a7a");

            var accessToken     = "accessToken1";
            var oioIdwsTokenKey = "tokenValue1";

            var tokenInformation = new OioIdwsToken();

            var authProperties = new AuthenticationProperties
            {
                Dictionary = { { "value", oioIdwsTokenKey } }
            };

            var tokenDataFormatMock = new Mock <ISecureDataFormat <AuthenticationProperties> >();

            tokenDataFormatMock
            .Setup(x => x.Unprotect(accessToken))
            .Returns(() => authProperties);

            var currentTime = DateTimeOffset.UtcNow; //ensure static time during test

            var timeMock = new Mock <ISystemClock>();

            // ReSharper disable once AccessToModifiedClosure
            timeMock
            .SetupGet(x => x.UtcNow)
            .Returns(() => currentTime);

            var storeMock = new Mock <ISecurityTokenStore>();

            storeMock
            .Setup(x => x.RetrieveTokenAsync(oioIdwsTokenKey))
            .Returns(() => Task.FromResult(tokenInformation));

            var options = new OioIdwsAuthorizationServiceOptions
            {
                AccessTokenIssuerPath            = new PathString("/accesstoken/issue"),
                AccessTokenRetrievalPath         = new PathString("/accesstoken"),
                IssuerAudiences                  = () => Task.FromResult(new IssuerAudiences[0]),
                TrustedWspCertificateThumbprints = new[] { "d9f10c97aa647727adb64a349bb037c5c23c9a7a" },
                CertificateValidator             = X509CertificateValidator.None, //no reason for tests to validate certs
                TokenDataFormat                  = tokenDataFormatMock.Object,
                SystemClock        = timeMock.Object,
                MaxClockSkew       = TimeSpan.FromMinutes(5),
                SecurityTokenStore = storeMock.Object,
            };

            using (var server = TestServerWithClientCertificate.Create(() => wspCertificate, app =>
            {
                app.UseOioIdwsAuthorizationService(options);
            }))
            {
                server.BaseAddress = new Uri("https://localhost/");

                {
                    //test that token content is checked properly
                    authProperties.ExpiresUtc = currentTime - options.MaxClockSkew.Add(TimeSpan.FromSeconds(1));

                    var response = await server.HttpClient.GetAsync($"/accesstoken?{accessToken}");

                    Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                    var json = JObject.Parse(await response.Content.ReadAsStringAsync());
                    Assert.AreEqual(1, json["expired"].Value <int>());
                }

                {
                    //test that stored token information is checked properly
                    authProperties.ExpiresUtc   = currentTime;
                    tokenInformation.ExpiresUtc = currentTime - options.MaxClockSkew.Add(TimeSpan.FromSeconds(1));

                    var response = await server.HttpClient.GetAsync($"/accesstoken?{accessToken}");

                    Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                    var json = JObject.Parse(await response.Content.ReadAsStringAsync());
                    Assert.AreEqual(1, json["expired"].Value <int>());
                }
            }
        }
Ejemplo n.º 12
0
        public async Task Authenticates_TokenExpired_IsUnauthorized()
        {
            var accessToken     = "dummy";
            var oioIdwsTokenKey = "token1";
            var token           = new OioIdwsToken
            {
                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(-1),
                Claims     = new[]
                {
                    new OioIdwsClaim
                    {
                        Value = "hans",
                        Type  = "name"
                    },
                }
            };

            var storeMock = new Mock <ISecurityTokenStore>();

            storeMock
            .Setup(x => x.RetrieveTokenAsync(oioIdwsTokenKey))
            .ReturnsAsync(token);

            var authProperties = new AuthenticationProperties
            {
                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(-1),
                Dictionary = { { "value", oioIdwsTokenKey } }
            };

            var tokenDataFormatMock = new Mock <ISecureDataFormat <AuthenticationProperties> >();

            tokenDataFormatMock
            .Setup(x => x.Unprotect(accessToken))
            .Returns(authProperties);

            using (var server = TestServer.Create(app =>
            {
                app
                .UseOioIdwsAuthentication(new OioIdwsAuthenticationOptions())
                .UseOioIdwsAuthorizationService(new OioIdwsAuthorizationServiceOptions
                {
                    AccessTokenIssuerPath = new PathString("/accesstoken/issue"),
                    IssuerAudiences = () => Task.FromResult(new[] { new IssuerAudiences("", "") }),
                    SecurityTokenStore = storeMock.Object,
                    TokenDataFormat = tokenDataFormatMock.Object,
                })
                .Use((context, next) =>
                {
                    if (context.Request.Path == new PathString("/wsp"))
                    {
                        context.Response.StatusCode = context.Request.User != null ? 200 : 401;
                    }
                    return(Task.FromResult(0));
                });
            }))
            {
                var client     = server.HttpClient;
                var authHeader = new AuthenticationHeaderValue("Bearer", accessToken);
                client.DefaultRequestHeaders.Authorization = authHeader;

                {
                    var response = await client.GetAsync("/wsp");

                    Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                    var errors = HttpHeaderUtils.ParseOAuthSchemeParameter(response.Headers.WwwAuthenticate.First().Parameter);
                    Assert.AreEqual(AuthenticationErrorCodes.InvalidToken, errors["error"]);
                    Assert.AreEqual("Token was expired", errors["error_description"]);
                }

                {
                    authProperties.ExpiresUtc = DateTimeOffset.Now.AddHours(1);

                    var response = await client.GetAsync("/wsp");

                    Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
                    var errors = HttpHeaderUtils.ParseOAuthSchemeParameter(response.Headers.WwwAuthenticate.First().Parameter);
                    Assert.AreEqual(AuthenticationErrorCodes.InvalidToken, errors["error"]);
                    Assert.AreEqual("Token was expired", errors["error_description"]);
                }
            }
        }
Ejemplo n.º 13
0
        public async Task Authenticates_UseInMemoryTokenStore_IsAuthorized()
        {
            var accessToken     = "dummy";
            var oioIdwsTokenKey = "token1";
            var token           = new OioIdwsToken
            {
                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(1),
                Claims     = new[]
                {
                    new OioIdwsClaim
                    {
                        Value = "hans",
                        Type  = "name"
                    },
                }
            };

            var storeMock = new Mock <ISecurityTokenStore>();

            storeMock
            .Setup(x => x.RetrieveTokenAsync(oioIdwsTokenKey))
            .ReturnsAsync(token);

            var tokenDataFormatMock = new Mock <ISecureDataFormat <AuthenticationProperties> >();

            tokenDataFormatMock
            .Setup(x => x.Unprotect(accessToken))
            .Returns(new AuthenticationProperties
            {
                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(1),
                Dictionary = { { "value", oioIdwsTokenKey } }
            });

            using (var server = TestServer.Create(app =>
            {
                app
                .UseOioIdwsAuthentication(new OioIdwsAuthenticationOptions())
                .UseOioIdwsAuthorizationService(new OioIdwsAuthorizationServiceOptions
                {
                    AccessTokenIssuerPath = new PathString("/accesstoken/issue"),
                    IssuerAudiences = () => Task.FromResult(new [] { new IssuerAudiences("", "") }),
                    SecurityTokenStore = storeMock.Object,
                    TokenDataFormat = tokenDataFormatMock.Object,
                })
                .Use((context, next) =>
                {
                    if (context.Request.Path == new PathString("/wsp"))
                    {
                        var name = ((ClaimsIdentity)context.Request.User.Identity).Claims.Single(x => x.Type == "name").Value;
                        context.Response.Write(name);
                    }
                    return(Task.FromResult(0));
                });
            }))
            {
                var client     = server.HttpClient;
                var authHeader = new AuthenticationHeaderValue("Bearer", accessToken);
                client.DefaultRequestHeaders.Authorization = authHeader;

                var response = await client.GetAsync("/wsp");

                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
                var str = await response.Content.ReadAsStringAsync();

                Assert.AreEqual("hans", str);
            }
        }