コード例 #1
0
        private async Task UpdateRedirectUris(string clientId, ClientRegisteration registration)
        {
            var redirectUriResponse = await _clientUriStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientUri.ClientId)} eq '{clientId}'"
            }).ConfigureAwait(false);

            foreach (var item in redirectUriResponse.Items)
            {
                if (!registration.RedirectUris.Any(u => u == item.Uri))
                {
                    await _clientUriStore.DeleteAsync(item.Id).ConfigureAwait(false);
                }
            }

            foreach (var redirectUri in registration.RedirectUris)
            {
                if (!redirectUriResponse.Items.Any(u => u.Uri == redirectUri))
                {
                    await _clientUriStore.CreateAsync(new ClientUri
                    {
                        ClientId = clientId,
                        Id       = Guid.NewGuid().ToString(),
                        Kind     = UriKinds.Cors | UriKinds.Redirect,
                        Uri      = redirectUri
                    }).ConfigureAwait(false);
                }
            }
        }
コード例 #2
0
        public async Task CreateAsync_should_validate_native_redirect_uri_scheme(string redirectUri)
        {
            var sut = TestUtils.CreateTestServer();

            sut.Services.GetRequiredService <TestUserService>()
            .SetTestUser(true, new Claim[] { new Claim("role", "Is4-Writer") });

            var client = sut.CreateClient();

            var registration = new ClientRegisteration
            {
                RedirectUris = new[]
                {
                    redirectUri
                },
                ApplicationType = "native"
            };

            // not redirect uri
            using var request  = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json");
            using var response = await client.PostAsync("/api/register", request);

            Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

            var content = await response.Content.ReadAsStringAsync();

            var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

            Assert.Equal("invalid_redirect_uri", error.Error);

            var uri = new Uri(redirectUri);

            Assert.Equal($"Invalid RedirectUri '{redirectUri}'.Native client cannot use standard '{uri.Scheme}' scheme, you must use a custom scheme such as 'net.pipe' or 'net.tcp', or 'http' scheme with 'localhost' host.", error.Error_description);
        }
コード例 #3
0
        private async Task UpdateGrantTypes(string clientId, ClientRegisteration registration)
        {
            var grantTypeResponse = await _clientGrantTypeStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientGrantType.ClientId)} eq '{clientId}'"
            }).ConfigureAwait(false);

            foreach (var item in grantTypeResponse.Items)
            {
                if (!registration.GrantTypes.Any(g => g == item.GrantType))
                {
                    await _clientGrantTypeStore.DeleteAsync(item.Id).ConfigureAwait(false);
                }
            }

            foreach (var grantType in registration.GrantTypes)
            {
                if (!grantTypeResponse.Items.Any(u => u.GrantType == grantType))
                {
                    await _clientGrantTypeStore.CreateAsync(new ClientGrantType
                    {
                        ClientId  = clientId,
                        Id        = Guid.NewGuid().ToString(),
                        GrantType = grantType
                    }).ConfigureAwait(false);
                }
            }
        }
コード例 #4
0
        private async Task UpdatePropertyAsync(string clientId, ClientRegisteration registration, PageResponse <ClientProperty> propertiesResponse, string values, string key)
        {
            var property = propertiesResponse.Items.FirstOrDefault(p => p.Key == key);

            if ((registration.Contacts == null || !registration.Contacts.Any()) && property != null)
            {
                await _clientPropertyStore.DeleteAsync(property.Id).ConfigureAwait(false);
            }
            if (registration.Contacts == null || !registration.Contacts.Any())
            {
                if (property == null)
                {
                    await _clientPropertyStore.CreateAsync(new ClientProperty
                    {
                        ClientId = clientId,
                        Id       = Guid.NewGuid().ToString(),
                        Key      = key,
                        Value    = values
                    }).ConfigureAwait(false);
                }
                else if (property.Value != values)
                {
                    property.Value = values;
                    await _clientPropertyStore.UpdateAsync(property).ConfigureAwait(false);
                }
            }
        }
コード例 #5
0
 private static void ValidateRedirectUri(ClientRegisteration registration, string uri, Uri redirectUri)
 {
     if (registration.ApplicationType == "web" &&
         registration.GrantTypes.Contains("implicit"))
     {
         if (redirectUri.Scheme != "https")
         {
             throw new RegistrationException("invalid_redirect_uri", $"Invalid RedirectUri '{uri}'. Implicit client must use 'https' scheme only.");
         }
         if (redirectUri.Host.ToUpperInvariant() == "LOCALHOST")
         {
             throw new RegistrationException("invalid_redirect_uri", $"Invalid RedirectUri '{uri}'. Implicit client cannot use 'localhost' host.");
         }
     }
     if (registration.ApplicationType == "native")
     {
         if (redirectUri.Scheme == Uri.UriSchemeGopher ||
             redirectUri.Scheme == Uri.UriSchemeHttps ||
             redirectUri.Scheme == Uri.UriSchemeNews ||
             redirectUri.Scheme == Uri.UriSchemeNntp)
         {
             throw new RegistrationException("invalid_redirect_uri", $"Invalid RedirectUri '{uri}'.Native client cannot use standard '{redirectUri.Scheme}' scheme, you must use a custom scheme such as 'net.pipe' or 'net.tcp', or 'http' scheme with 'localhost' host.");
         }
         if (redirectUri.Scheme == Uri.UriSchemeHttp && redirectUri.Host.ToUpperInvariant() != "LOCALHOST")
         {
             throw new RegistrationException("invalid_redirect_uri", $"Invalid RedirectUri '{uri}'.Only 'localhost' host is allowed for 'http' scheme and 'native' client.");
         }
     }
 }
コード例 #6
0
        private async Task UpdatePropertiesAsync(string clientId, ClientRegisteration registration)
        {
            var propertiesResponse = await _clientPropertyStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientProperty.ClientId)} eq '{clientId}' and ({nameof(ClientProperty.Key)} eq 'contacts' or {nameof(ClientProperty.Key)} eq 'responseTypes')"
            }).ConfigureAwait(false);

            await UpdatePropertyAsync(clientId, registration, propertiesResponse, registration.Contacts != null?string.Join("; ", registration.Contacts) : null, "contacts").ConfigureAwait(false);
            await UpdatePropertyAsync(clientId, registration, propertiesResponse, registration.ResponseTypes != null?string.Join("; ", registration.ResponseTypes) : null, "responseType").ConfigureAwait(false);
        }
コード例 #7
0
        private void Validate(ClientRegisteration registration, Dictionary <string, object> discovery)
        {
            registration.GrantTypes ??= new List <string>
            {
                "authorization_code"
            };

            if (registration.RedirectUris == null || !registration.RedirectUris.Any())
            {
                throw new RegistrationException("invalid_redirect_uri", "RedirectUri is required.");
            }

            if (registration.ApplicationType != "web" && registration.ApplicationType != "native")
            {
                throw new RegistrationException("invalid_application_type", $"ApplicationType '{registration.ApplicationType}' is invalid. It must be 'web' or 'native'.");
            }

            var validationOptions = _identityServerOptions1.Validation;
            var redirectUriList   = new List <Uri>(registration.RedirectUris.Count());

            foreach (var uri in registration.RedirectUris)
            {
                if (validationOptions.InvalidRedirectUriPrefixes
                    .Any(scheme => uri?.StartsWith(scheme, StringComparison.OrdinalIgnoreCase) == true))
                {
                    throw new RegistrationException("invalid_redirect_uri", $"RedirectUri '{uri}' uses invalid scheme. If this scheme should be allowed, then configure it via ValidationOptions.");
                }
                if (!Uri.TryCreate(uri, UriKind.Absolute, out var redirectUri))
                {
                    throw new RegistrationException("invalid_redirect_uri", $"RedirectUri '{uri}' is not valid.");
                }

                ValidateRedirectUri(registration, uri, redirectUri);

                redirectUriList.Add(redirectUri);
            }

            ValidateUris(redirectUriList, registration.LogoUris, "invalid_logo_uri", "LogoUri");

            ValidateUris(redirectUriList, registration.PolicyUris, "invalid_policy_uri", "PolicyUri");

            if (registration.GrantTypes == null || !registration.GrantTypes.Any())
            {
                registration.GrantTypes = new[] { "authorization_code" };
            }
            ValidateGrantType(registration.GrantTypes, discovery["grant_types_supported"] as IEnumerable <string>);

            if (registration.ResponseTypes == null || !registration.ResponseTypes.Any())
            {
                registration.ResponseTypes = new[] { "code" };
            }

            ValidateResponseType(registration.GrantTypes, registration.ResponseTypes, discovery["response_types_supported"] as IEnumerable <string>);
        }
コード例 #8
0
        private async Task UpdateClient(ClientRegisteration registration, Client client)
        {
            client.ClientUri = registration.ClientUris?.FirstOrDefault(u => u.Culture == null)?.Value ??
                               registration.ClientUris?.FirstOrDefault()?.Value;
            client.LogoUri = registration.LogoUris?.FirstOrDefault(u => u.Culture == null)?.Value ??
                             registration.LogoUris?.FirstOrDefault()?.Value;
            client.PolicyUri = registration.TosUris?.FirstOrDefault(u => u.Culture == null)?.Value ??
                               registration.TosUris?.FirstOrDefault()?.Value;
            client.TosUri = registration.TosUris?.FirstOrDefault(u => u.Culture == null)?.Value ??
                            registration.TosUris?.FirstOrDefault()?.Value;

            await _clientStore.UpdateAsync(client).ConfigureAwait(false);
        }
コード例 #9
0
 private void ValidateCaller(ClientRegisteration registration, HttpContext httpContext)
 {
     if (!(httpContext.User?.IsInRole(SharedConstants.WRITER) ?? false))
     {
         var allowedContact = _dymamicClientRegistrationOptions.AllowedContacts?.FirstOrDefault(c => registration.Contacts?.Contains(c.Contact) ?? false);
         if (allowedContact == null)
         {
             throw new ForbiddenException();
         }
         if (!allowedContact.AllowedHosts.Any(h => registration.RedirectUris.Select(u => new Uri(u)).Any(u => u.Host == h)))
         {
             throw new ForbiddenException();
         }
     }
 }
コード例 #10
0
        public void WriteJson_should_serialize_localizable_properties()
        {
            var registration = new ClientRegisteration
            {
                ClientNames = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Culture = "fr-FR",
                        Value   = "test"
                    }
                },
                ApplicationType = "native",
                Contacts        = new List <string>
                {
                    "test"
                }
            };

            var result = JsonConvert.SerializeObject(registration);

            Assert.Contains("client_name#fr-FR", result);
        }
コード例 #11
0
 public Task <ClientRegisteration> UpdateAsync(string clientId, [FromBody] ClientRegisteration registeration)
 => _registerClientService.UpdateRegistrationAsync(clientId, registeration, $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/");
コード例 #12
0
 public Task <ClientRegisteration> CreateAsync([FromBody] ClientRegisteration registeration)
 => _registerClientService.RegisterAsync(registeration, HttpContext);
コード例 #13
0
        public async Task DeleteAsync_should_delete_client()
        {
            var sut = TestUtils.CreateTestServer();

            sut.Services.GetRequiredService <TestUserService>()
            .SetTestUser(true, new Claim[] { new Claim("role", "Is4-Writer") });

            var client = sut.CreateClient();

            var registration = new ClientRegisteration
            {
                ClientNames = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "test"
                    },
                },
                RedirectUris = new List <string>
                {
                    "http://localhost"
                }
            };

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                var content = await response.Content.ReadAsStringAsync();

                registration = JsonConvert.DeserializeObject <ClientRegisteration>(content);

                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
                Assert.NotNull(registration.RegistrationToken);
            }

            using (var message = new HttpRequestMessage
            {
                Method = HttpMethod.Delete,
                RequestUri = new Uri(registration.RegistrationUri)
            })
            {
                message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", registration.RegistrationToken);

                using var response = await client.SendAsync(message);

                Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
            }

            using (var message = new HttpRequestMessage
            {
                Method = HttpMethod.Get,
                RequestUri = new Uri(registration.RegistrationUri)
            })
            {
                message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", registration.RegistrationToken);

                using var response = await client.SendAsync(message);

                Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
            }
        }
コード例 #14
0
        public async Task CreateAsync_should_validate_caller()
        {
            using var sut = TestUtils.CreateTestServer(configurationOverrides: new Dictionary <string, string>
            {
                ["DynamicClientRegistrationOptions:AllowedContacts:0:Contact"]        = "test",
                ["DynamicClientRegistrationOptions:AllowedContacts:0:AllowedHosts:0"] = "localhost",
            });

            var client = sut.CreateClient();

            var registration = new ClientRegisteration
            {
                ClientNames = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "test"
                    },
                },
                RedirectUris = new List <string>
                {
                    "http://localhost"
                },
                Contacts = new[]
                {
                    "test"
                }
            };

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                var content = await response.Content.ReadAsStringAsync();

                var result = JsonConvert.DeserializeObject <ClientRegisteration>(content);

                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
                Assert.NotNull(result.RegistrationToken);
                Assert.NotNull(result.RegistrationUri);
            }

            registration.RedirectUris = new[]
            {
                "http://forbidenn"
            };

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);


                Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
            }


            registration.Contacts = new[]
            {
                "forbidenn"
            };

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);


                Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
            }
        }
コード例 #15
0
        public async Task CreateAsync_should_validate_request()
        {
            using var sut = TestUtils.CreateTestServer();
            sut.Services.GetRequiredService <TestUserService>()
            .SetTestUser(true, new Claim[]
            {
                new Claim("role", "Is4-Writer"),
                new Claim(JwtClaimTypes.Scope, SharedConstants.ADMINSCOPE)
            });

            var client = sut.CreateClient();

            var registration = new ClientRegisteration
            {
            };

            // not redirect uri
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);

                Assert.Equal("RedirectUri is required.", error.Error_description);
            }

            registration.RedirectUris = new List <string>
            {
            };

            // empty redirect uris
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("RedirectUri is required.", error.Error_description);
            }

            registration.RedirectUris = new List <string>
            {
                "test"
            };

            // invalid uri prefix
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("RedirectUri 'test' is not valid.", error.Error_description);
            }


            registration.RedirectUris = new List <string>
            {
                "ssh:test"
            };

            // invalid uri prefix
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("RedirectUri 'ssh:test' uses invalid scheme. If this scheme should be allowed, then configure it via ValidationOptions.", error.Error_description);
            }

            registration.RedirectUris = new List <string>
            {
                "http://localhost"
            };
            registration.LogoUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "test"
                }
            };

            // invalid logo uris
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_logo_uri", error.Error);
                Assert.Equal("LogoUri 'test' is not valid.", error.Error_description);
            }

            registration.LogoUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "http://test"
                }
            };

            // logo uri don't match redirect uri host
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_logo_uri", error.Error);
                Assert.Equal("LogoUri 'http://test' host doesn't match a redirect uri host.", error.Error_description);
            }

            registration.LogoUris   = null;
            registration.PolicyUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "test"
                }
            };

            // invalid logo uris
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_policy_uri", error.Error);
                Assert.Equal("PolicyUri 'test' is not valid.", error.Error_description);
            }

            registration.PolicyUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "http://test"
                }
            };

            // policy uri don't match redirect uri host
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_policy_uri", error.Error);
                Assert.Equal("PolicyUri 'http://test' host doesn't match a redirect uri host.", error.Error_description);
            }

            registration.PolicyUris = null;
            registration.GrantTypes = new[] { "invalid" };

            // invalid grant type
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_grant_type", error.Error);
                Assert.Equal("GrantType 'invalid' is not supported.", error.Error_description);
            }

            registration.GrantTypes    = null;
            registration.ResponseTypes = new[] { "invalid" };

            // invalid reponse type
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_response_type", error.Error);
                Assert.Equal("ResponseType 'invalid' is not supported.", error.Error_description);
            }

            registration.GrantTypes   = new[] { "implicit" };
            registration.RedirectUris = new[]
            {
                "https://test"
            };
            registration.ResponseTypes = new[] { "code" };

            // invalid reponse type
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_response_type", error.Error);
                Assert.Equal("No GrantType 'authorization_code' for ResponseType 'code' found in grant_types.", error.Error_description);
            }

            registration.GrantTypes    = null;
            registration.ResponseTypes = new[] { "id_token" };

            // reponse / grant type doesn't match
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_response_type", error.Error);
                Assert.Equal("No GrantType 'implicit' for ResponseType 'id_token' found in grant_types.", error.Error_description);
            }

            registration.ResponseTypes = new[] { "token id_token" };

            // reponse / grant type doesn't match
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_response_type", error.Error);
                Assert.Equal("No GrantType 'implicit' for ResponseType 'token id_token' found in grant_types.", error.Error_description);
            }

            registration.ResponseTypes = new[] { "code token id_token" };
            registration.GrantTypes    = new[] { "implicit" };

            // reponse / grant type doesn't match
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_response_type", error.Error);
                Assert.Equal("No GrantType 'authorization_code' for ResponseType 'code token id_token' found in grant_types.", error.Error_description);
            }

            registration.ResponseTypes = new[] { "token" };
            registration.RedirectUris  = new[]
            {
                "http://test"
            };
            // invalid scheme for grant type implicit

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("Invalid RedirectUri 'http://test'. Implicit client must use 'https' scheme only.", error.Error_description);
            }

            registration.RedirectUris = new[]
            {
                "https://localhost"
            };
            // invalid host for grant type implicit

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("Invalid RedirectUri 'https://localhost'. Implicit client cannot use 'localhost' host.", error.Error_description);
            }

            registration.RedirectUris = new[]
            {
                "https://localhost"
            };
            // invalid host for grant type implicit

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("Invalid RedirectUri 'https://localhost'. Implicit client cannot use 'localhost' host.", error.Error_description);
            }

            registration.ResponseTypes = null;
            registration.GrantTypes    = null;

            registration.ApplicationType = "native";
            registration.RedirectUris    = new[]
            {
                "http://test"
            };

            // invalid host for native client

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_redirect_uri", error.Error);
                Assert.Equal("Invalid RedirectUri 'http://test'.Only 'localhost' host is allowed for 'http' scheme and 'native' client.", error.Error_description);
            }

            registration.ApplicationType = "invalid";

            // invalid application type
            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                var content = await response.Content.ReadAsStringAsync();

                var error = JsonConvert.DeserializeObject <RegistrationProblemDetail>(content);

                Assert.Equal("invalid_application_type", error.Error);
                Assert.Equal("ApplicationType 'invalid' is invalid. It must be 'web' or 'native'.", error.Error_description);
            }
        }
コード例 #16
0
        public async Task CreateAsync_should_register_a_new_client()
        {
            var configuration = new Dictionary <string, string>
            {
                ["Seed"] = "false"
            };

            using var sut = TestUtils.CreateTestServer(configurationOverrides: configuration);

            sut.Services.GetRequiredService <TestUserService>()
            .SetTestUser(true, new Claim[]
            {
                new Claim("role", "Is4-Writer"),
                new Claim(JwtClaimTypes.Scope, SharedConstants.ADMINSCOPE)
            });

            var client = sut.CreateClient();

            var registration = new ClientRegisteration
            {
                ClientNames = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "test"
                    },
                },
                RedirectUris = new List <string>
                {
                    "http://localhost"
                }
            };

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                var content = await response.Content.ReadAsStringAsync();

                var result = JsonConvert.DeserializeObject <ClientRegisteration>(content);

                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
                Assert.NotNull(result.RegistrationToken);
                Assert.NotNull(result.RegistrationUri);
            }

            registration.Jwks = new JsonWebKeys
            {
                Keys = new[]
                {
                    new JsonWebKey
                    {
                        kty = "RSA",
                        e   = "AQAB",
                        use = "sig",
                        alg = "RS256",
                        n   = "qBulUDaYV027shwCq82LKIevXdQL2pCwXktQgf2TT3c496pxGdRuxcN_MHGKWNOGQsDLuAVk6NjxYF95obDUFrDiugMuXrvptPrTO8dzTX83k_6ngtjOtx2UrTk_7f0EYNrusykrsB-cOvCMREsfktlsavvMKBGrzpxaHlRxcSsMxzB0dddDSlH8mxlzOGcbBuvZnbNg0EUuQC4jvM9Gy6gUEcoU0S19XnUcgwLGLPfIX2dMO4FxTAsaaTYT7msxGMBNIVUTVnL0HctYr0YVYu0hD9rePnvxJ_-OwOdxIETQlR9vp61xFr4juzyyMWTrjCACxxLm-CyEQGjwx2YZaw"
                    }
                }
            };
            registration.RedirectUris = new List <string>
            {
                "https://localhost"
            };
            registration.ClientNames = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Culture = "fr-FR",
                    Value   = "test"
                },
            };

            registration.ClientUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "https://localhost"
                },
                new LocalizableProperty
                {
                    Culture = "fr-FR",
                    Value   = "https://localhost/fr-FR"
                },
            };

            registration.LogoUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "https://localhost"
                },
                new LocalizableProperty
                {
                    Culture = "fr-FR",
                    Value   = "https://localhost/fr-FR"
                },
            };

            registration.PolicyUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "https://localhost"
                },
                new LocalizableProperty
                {
                    Culture = "fr-FR",
                    Value   = "https://localhost/fr-FR"
                },
            };

            registration.TosUris = new List <LocalizableProperty>
            {
                new LocalizableProperty
                {
                    Value = "https://localhost"
                },
                new LocalizableProperty
                {
                    Culture = "fr-FR",
                    Value   = "https://localhost/fr-FR"
                },
            };

            registration.JwksUri = "https://jwk";

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
            }
        }
コード例 #17
0
        /// <summary>
        /// Registers the asynchronous.
        /// </summary>
        /// <param name="registration">The client registration.</param>
        /// <param name="httpContext">The HTTP context.</param>
        /// <returns></returns>
        public async Task <ClientRegisteration> RegisterAsync(ClientRegisteration registration, HttpContext httpContext)
        {
            var uri       = $"{httpContext.Request.Scheme}://{httpContext.Request.Host}/";
            var discovery = await _discoveryResponseGenerator.CreateDiscoveryDocumentAsync(uri, uri).ConfigureAwait(false);

            ValidateCaller(registration, httpContext);
            Validate(registration, discovery);

            var clientName = registration.ClientNames?.FirstOrDefault(n => n.Culture == null)?.Value ??
                             registration.ClientNames?.FirstOrDefault()?.Value ?? Guid.NewGuid().ToString();
            var existing = await _clientStore.GetAsync(clientName, null).ConfigureAwait(false);

            registration.Id = existing != null?Guid.NewGuid().ToString() : clientName;

            registration.Id = registration.Id.Contains(' ') ? Guid.NewGuid().ToString() : registration.Id;
            var secret = Guid.NewGuid().ToString();

            var serializerSettings = new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore
            };
            var jwkKeys     = registration.Jwks?.Keys;
            var sercretList = jwkKeys != null?jwkKeys.Select(k => new ClientSecret
            {
                Id    = Guid.NewGuid().ToString(),
                Type  = IdentityServer4.IdentityServerConstants.SecretTypes.JsonWebKey,
                Value = JsonConvert.SerializeObject(k, serializerSettings)
            }).ToList() : new List <ClientSecret>();

            sercretList.Add(new ClientSecret
            {
                Id    = Guid.NewGuid().ToString(),
                Type  = IdentityServer4.IdentityServerConstants.SecretTypes.SharedSecret,
                Value = secret
            });

            var client = new Client
            {
                AllowedGrantTypes = registration.GrantTypes.Select(grant => new ClientGrantType
                {
                    Id        = Guid.NewGuid().ToString(),
                    GrantType = grant
                }).ToList(),
                AccessTokenLifetime          = _defaultValues.AccessTokenLifetime,
                AbsoluteRefreshTokenLifetime = _defaultValues.AbsoluteRefreshTokenLifetime,
                AccessTokenType             = (int)_defaultValues.AccessTokenType,
                AllowOfflineAccess          = registration.ApplicationType == "web" && registration.GrantTypes.Contains("refresh_token"),
                AllowAccessTokensViaBrowser = registration.ApplicationType == "web",
                AllowedScopes = new List <ClientScope> {
                    new ClientScope
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Scope = "openid"
                    },
                    new ClientScope
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Scope = "profile"
                    },
                    new ClientScope
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Scope = "address"
                    },
                    new ClientScope
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Scope = "email"
                    },
                    new ClientScope
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Scope = "phone"
                    }
                },
                AllowRememberConsent             = _defaultValues.AllowRememberConsent,
                AllowPlainTextPkce               = _defaultValues.AllowPlainTextPkce,
                AlwaysIncludeUserClaimsInIdToken = _defaultValues.AlwaysIncludeUserClaimsInIdToken,
                AlwaysSendClientClaims           = _defaultValues.AlwaysSendClientClaims,
                AuthorizationCodeLifetime        = _defaultValues.AuthorizationCodeLifetime,
                BackChannelLogoutSessionRequired = !string.IsNullOrEmpty(_defaultValues.BackChannelLogoutUri),
                BackChannelLogoutUri             = _defaultValues.BackChannelLogoutUri,
                ClientClaimsPrefix               = _defaultValues.ClientClaimsPrefix,
                ClientName         = clientName,
                ClientSecrets      = sercretList,
                ClientUri          = registration.ClientUris?.FirstOrDefault(u => u.Culture == null)?.Value ?? registration.ClientUris?.FirstOrDefault()?.Value,
                ConsentLifetime    = _defaultValues.ConsentLifetime,
                Description        = _defaultValues.Description,
                DeviceCodeLifetime = _defaultValues.DeviceCodeLifetime,
                Enabled            = true,
                EnableLocalLogin   = _defaultValues.EnableLocalLogin,
                FrontChannelLogoutSessionRequired = !string.IsNullOrEmpty(_defaultValues.FrontChannelLogoutUri),
                FrontChannelLogoutUri             = _defaultValues.FrontChannelLogoutUri,
                Id = registration.Id,
                IdentityTokenLifetime = _defaultValues.IdentityTokenLifetime,
                IncludeJwtId          = _defaultValues.IncludeJwtId,
                LogoUri             = registration.LogoUris?.FirstOrDefault(u => u.Culture == null)?.Value ?? registration.LogoUris?.FirstOrDefault()?.Value,
                NonEditable         = false,
                PairWiseSubjectSalt = _defaultValues.PairWiseSubjectSalt,
                ProtocolType        = _defaultValues.ProtocolType,
                RedirectUris        = registration.RedirectUris.Select(u => new ClientUri
                {
                    Id   = Guid.NewGuid().ToString(),
                    Kind = UriKinds.Cors | UriKinds.Redirect,
                    Uri  = u
                }).ToList(),
                RefreshTokenExpiration = (int)_defaultValues.RefreshTokenExpiration,
                RefreshTokenUsage      = (int)_defaultValues.RefreshTokenUsage,
                RequireClientSecret    = false,
                RequireConsent         = _defaultValues.RequireConsent,
                RequirePkce            = false,
                Resources = registration.ClientNames.Where(n => n.Culture != null)
                            .Select(n => new ClientLocalizedResource
                {
                    Id           = Guid.NewGuid().ToString(),
                    CultureId    = n.Culture,
                    ResourceKind = EntityResourceKind.DisplayName,
                    Value        = n.Value
                })
                            .Union(registration.ClientUris != null ? registration.ClientUris.Where(u => u.Culture != null).Select(u => new ClientLocalizedResource
                {
                    Id           = Guid.NewGuid().ToString(),
                    CultureId    = u.Culture,
                    ResourceKind = EntityResourceKind.ClientUri,
                    Value        = u.Value
                }) : new List <ClientLocalizedResource>(0))
                            .Union(registration.LogoUris != null ? registration.LogoUris.Where(u => u.Culture != null).Select(u => new ClientLocalizedResource
                {
                    Id           = Guid.NewGuid().ToString(),
                    CultureId    = u.Culture,
                    ResourceKind = EntityResourceKind.LogoUri,
                    Value        = u.Value
                }) : new List <ClientLocalizedResource>(0))
                            .Union(registration.PolicyUris != null ? registration.PolicyUris.Where(u => u.Culture != null).Select(u => new ClientLocalizedResource
                {
                    Id           = Guid.NewGuid().ToString(),
                    CultureId    = u.Culture,
                    ResourceKind = EntityResourceKind.PolicyUri,
                    Value        = u.Value
                }) : new List <ClientLocalizedResource>(0))
                            .Union(registration.TosUris != null ? registration.TosUris.Where(u => u.Culture != null).Select(u => new ClientLocalizedResource
                {
                    Id           = Guid.NewGuid().ToString(),
                    CultureId    = u.Culture,
                    ResourceKind = EntityResourceKind.TosUri,
                    Value        = u.Value
                }) : new List <ClientLocalizedResource>(0))
                            .ToList(),
                Properties = new List <ClientProperty>
                {
                    new ClientProperty
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Key   = "applicationType",
                        Value = registration.ApplicationType
                    }
                }.Union(registration.Contacts != null ? new List <ClientProperty>
                {
                    new ClientProperty
                    {
                        Id    = Guid.NewGuid().ToString(),
                        Key   = "contacts",
                        Value = string.Join("; ", registration.Contacts)
                    }
                } : new List <ClientProperty>(0))
                .ToList(),
                SlidingRefreshTokenLifetime      = _defaultValues.SlidingRefreshTokenLifetime,
                UpdateAccessTokenClaimsOnRefresh = _defaultValues.UpdateAccessTokenClaimsOnRefresh,
                UserCodeType    = _defaultValues.UserCodeType,
                UserSsoLifetime = _defaultValues.UserSsoLifetime,
                PolicyUri       = registration.TosUris?.FirstOrDefault(u => u.Culture == null)?.Value ?? registration.TosUris?.FirstOrDefault()?.Value,
                TosUri          = registration.TosUris?.FirstOrDefault(u => u.Culture == null)?.Value ?? registration.TosUris?.FirstOrDefault()?.Value,
            };

            client.RegistrationToken = Guid.NewGuid();

            await _clientStore.CreateAsync(client).ConfigureAwait(false);

            registration.RegistrationToken    = client.RegistrationToken.ToString();
            registration.RegistrationUri      = $"{discovery["registration_endpoint"]}/{client.Id}";
            registration.JwksUri              = discovery["jwks_uri"].ToString();
            registration.ClientSecret         = secret;
            registration.ClientSecretExpireAt = 0;

            return(registration);
        }
コード例 #18
0
        public async Task GetAsync_should_return_registration()
        {
            using var sut = TestUtils.CreateTestServer();
            sut.Services.GetRequiredService <TestUserService>()
            .SetTestUser(true, new Claim[]
            {
                new Claim(JwtClaimTypes.Role, "Is4-Writer"),
                new Claim(JwtClaimTypes.Scope, SharedConstants.ADMINSCOPE)
            });

            var client = sut.CreateClient();

            var registration = new ClientRegisteration
            {
                ClientNames = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "test"
                    },
                },
                RedirectUris = new List <string>
                {
                    "https://localhost"
                },
                ClientUris = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "https://localhost"
                    },
                    new LocalizableProperty
                    {
                        Culture = "fr-FR",
                        Value   = "https://localhost/fr-FR"
                    },
                },
                LogoUris = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "https://localhost"
                    },
                    new LocalizableProperty
                    {
                        Culture = "fr-FR",
                        Value   = "https://localhost/fr-FR"
                    },
                },
                PolicyUris = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "https://localhost"
                    },
                    new LocalizableProperty
                    {
                        Culture = "fr-FR",
                        Value   = "https://localhost/fr-FR"
                    },
                },
                TosUris = new List <LocalizableProperty>
                {
                    new LocalizableProperty
                    {
                        Value = "https://localhost"
                    },
                    new LocalizableProperty
                    {
                        Culture = "fr-FR",
                        Value   = "https://localhost/fr-FR"
                    },
                },
                ResponseTypes = new[]
                {
                    "code"
                }
            };

            using (var request = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json"))
            {
                using var response = await client.PostAsync("/api/register", request);

                var content = await response.Content.ReadAsStringAsync();

                registration = JsonConvert.DeserializeObject <ClientRegisteration>(content);

                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
                Assert.NotNull(registration.RegistrationToken);
            }

            using (var message = new HttpRequestMessage
            {
                Method = HttpMethod.Get,
                RequestUri = new Uri(registration.RegistrationUri)
            })
            {
                message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", registration.RegistrationToken);

                using var response = await client.SendAsync(message);

                var content = await response.Content.ReadAsStringAsync();

                var result = JsonConvert.DeserializeObject <ClientRegisteration>(content);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                Assert.Null(result.RegistrationToken);
                Assert.Null(result.RegistrationUri);
            }
        }
コード例 #19
0
        /// <summary>
        /// Updates the registration asynchronous.
        /// </summary>
        /// <param name="clientId">The client identifier.</param>
        /// <param name="registration">The client.</param>
        /// <param name="uri">The URI.</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task <ClientRegisteration> UpdateRegistrationAsync(string clientId, ClientRegisteration registration, string uri)
        {
            var client = await GetClientAsync(clientId).ConfigureAwait(false);

            var discovery = await _discoveryResponseGenerator.CreateDiscoveryDocumentAsync(uri, uri).ConfigureAwait(false);

            Validate(registration, discovery);
            await UpdateClient(registration, client).ConfigureAwait(false);
            await UpdateRedirectUris(clientId, registration).ConfigureAwait(false);
            await UpdateGrantTypes(clientId, registration).ConfigureAwait(false);

            var resourceResponse = await _clientResourceStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientGrantType.ClientId)} eq '{clientId}'"
            }).ConfigureAwait(false);

            var items          = resourceResponse.Items;
            var clientNameList = registration.ClientNames?.Where(n => n.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var clientUriList  = registration.ClientUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var logoUriList    = registration.LogoUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var policyUriList  = registration.PolicyUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var tosUriList     = registration.TosUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();

            foreach (var item in items)
            {
                await DeleteItemAsync(clientNameList, clientUriList, logoUriList, policyUriList, tosUriList, item).ConfigureAwait(false);
            }

            await AddResourceAsync(clientId, items, clientNameList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, clientUriList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, logoUriList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, policyUriList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, tosUriList).ConfigureAwait(false);

            await UpdatePropertiesAsync(clientId, registration).ConfigureAwait(false);

            registration.RegistrationToken    = null;
            registration.RegistrationUri      = null;
            registration.JwksUri              = discovery["jwks_uri"].ToString();
            registration.ClientSecret         = client.ClientSecrets.FirstOrDefault()?.Value;
            registration.ClientSecretExpireAt = client.ClientSecrets.Any() ? (int?)0 : null;

            return(registration);
        }