-
Notifications
You must be signed in to change notification settings - Fork 4k
Self-registering services #1248
Comments
It seems to be a general problem with all open ID specs. I would like to see some formal method for establishing a trust framework for all back channel servers. Any one up for that?
..Tom's phone
On Jun 12, 2017, at 1:51 PM, Paul Crossan <notifications@github.com<mailto:notifications@github.com>> wrote:
* I read and understood how to enable logging<https://identityserver4.readthedocs.io/en/release/topics/logging.html>
Are there any patterns or best practices for registering new ApiResources and their scopes with IdentityServer? In our environment, we have multiple APIs (Resource Servers) which we would like to keep decoupled from our Identity Server implementation. Each of those APIs would need to somehow register themselves with Identity Server. This could possibly happen on deployment or on startup. We've seen the API Client Registration specification here<http://openid.net/specs/openid-connect-registration-1_0.html>. We will also need to do something like this as well for our internal API Clients. What would you recommend as a secure way of registering these? Are you planning on releasing any new endpoints to handle either of these?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#1248>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AKxq1itUvcfCittgzpYwQq8VbiNf4FjTks5sDaTGgaJpZM4N3qtu>.
|
We discussed this a couple of times. Registration is nothing we gonna build into the core of IdentityServer. But you could easily add the "write" endpoints yourself. Since we think this is more of a task for an admin UI/API - see here: |
Yes, we could add the write end points ourselves but, as @TomCJones mentioned, the difficulty is setting up some kind of dynamic back channel trust mechanism that is sufficiently secure and, at the same time, isn't overly burdensome for the services that are self registering. I'd be very curious what others are doing with regard to this. @TomCJones if you have thoughts I'd love to hear them. Here are some quick initial thoughts:
Obviously some of these thoughts are specific to a 1st party scenario running in the same network. |
I wrote up some ideas on this here: https://wiki.idesg.org/wiki/index.php?title=Trust_Framework_Membership_Validation I would welcome any comments about it as I believe we need to create some sort of standard or best practice in this area. |
I would recommend you start a separate project around that - I don't see this as a core IdentityServer concern. Keep us posted on the progress though. |
@TomCJones @agilenut Have either of you progressed forward with this? I also need to register services dynamically. |
Well, there are a few developments, mostly in the UK. I earlier decided that the OpenID federation docs were not helpful. The UK references are not final, and require a certificate for each "member", which I would not mandate. But you can get some ideas of the json exchanges here: https://openbanking.atlassian.net/wiki/spaces/DZ/pages/28737919/The+Open+Banking+Directory+-+v1.1.1-rc1#TheOpenBankingDirectory-v1.1.1-rc1-GenerateSoftwareStatementAssertion I am working on 2fa now, but remain interested in some sort of membership end-point at some time. |
btw, I look at this as "just" an endpoint with a Get query and a json response. I would be happy to move a real world implementation into a standards track somewhere. I would expect that anon access is fine, but would like to hear from others if that makes sense. |
@nicbavetta We went forward with the approach that I outlined in my earlier comment. It's similar to the Dynamic Client Registration spec. We are doing this for both Clients and API Resources. This approach seems like it will work for us but it is still very early. APIs are just starting to be ported over to the new registration model. So, we'll see how well it works in practice. Again, our scenario is that we wanted several different 1st party development teams to be able to quickly spin up new Clients and APIs without requiring tedious environment configurations. Keeping registration within a 1st party trust boundary makes our scenario easier than a public or true 3rd party registration scenario. We were able to leverage our continuous deployment tooling to securely store and distribute the secret material to each new API that needed to register itself with our Identity Server implementation as that API came online. An added benefit of this style of self-registration is that the API Resource and Client configuration becomes code in the registered API that goes through our normal PR approval process. There are several areas of improvement that we'd like to see. One area that we have discussed is the desire for a kind of scope policy which would allow a team creating an API to define the criteria that should be met to allow a client to register for an allowed scope. |
@agilenut Do you have any code that can be shared for this? I am only interested in the 1st party trust boundary. |
@nicbavetta Sorry. At this time, all of the code that we have is interwoven with quite a bit of proprietary logic that I cannot currently share. |
I was in need of client registration so I wrote some code after peeking at the OpenID Connect Dynamic Client Registration 1.0 and RFC 7591 (OAuth 2.0 Dynamic Registration) specifications. The code is not compliant to the specifications.
I use the IdentityServer4.EntityFramework package hence gets using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using IdentityModel;
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Example.IdentityServer.Models;
namespace Example.IdentityServer.Controllers
{
[Route("connect/register")]
[ApiController]
// [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Consumes("application/json")]
[Produces("application/json")]
public class ClientController : ControllerBase
{
private readonly ConfigurationDbContext _context;
public ClientController(ConfigurationDbContext context)
{
_context = context;
}
// POST: connect/register
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> PostAsync(ClientRegistrationModel model)
{
if (!Request.IsHttps)
{
return BadRequest("HTTPS is required at this endpoint.");
}
if (model.GrantTypes == null)
{
model.GrantTypes = new List<string> { OidcConstants.GrantTypes.AuthorizationCode };
}
if (model.GrantTypes.Any(x => x == OidcConstants.GrantTypes.Implicit) || model.GrantTypes.Any(x => x == OidcConstants.GrantTypes.AuthorizationCode))
{
if (!model.RedirectUris.Any())
{
return BadRequest("A redirect URI is required for the supplied grant type.");
}
if (model.RedirectUris.Any(redirectUri => !Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)))
{
return BadRequest("One or more of the redirect URIs are invalid.");
}
}
var response = new ClientRegistrationResponse
{
ClientId = Guid.NewGuid().ToString(),
ClientSecret = GenerateSecret(32),
ClientName = model.ClientName,
ClientUri = model.ClientUri,
LogoUri = model.LogoUri,
GrantTypes = model.GrantTypes,
RedirectUris = model.RedirectUris,
Scope = model.Scope
};
var client = new Client
{
ClientId = response.ClientId,
ClientName = response.ClientName,
ClientSecrets = new List<ClientSecret>(),
ClientUri = model.ClientUri,
LogoUri = model.LogoUri,
AllowedGrantTypes = new List<ClientGrantType>(),
AllowedScopes = new List<ClientScope>(),
RedirectUris = new List<ClientRedirectUri>()
};
client.ClientSecrets.Add(new ClientSecret
{
Value = response.ClientSecret,
Client = client
});
foreach (var scope in model.Scope.Split())
{
client.AllowedScopes.Add(new ClientScope
{
Scope = scope,
Client = client
});
}
foreach (var grantType in model.GrantTypes)
{
client.AllowedGrantTypes.Add(new ClientGrantType { Client = client, GrantType = grantType });
}
foreach (var redirectUri in model.RedirectUris)
{
client.RedirectUris.Add(new ClientRedirectUri { Client = client, RedirectUri = redirectUri });
}
_context.Clients.Add(client);
await _context.SaveChangesAsync();
return Ok(response);
}
} using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using IdentityModel;
using Newtonsoft.Json;
namespace Example.IdentityServer.Models
{
public class ClientRegistrationModel
{
[JsonProperty(OidcConstants.ClientMetadata.ClientName)]
public string ClientName { get; set; }
[JsonProperty(OidcConstants.ClientMetadata.ClientUri)]
[Url]
public string ClientUri { get; set; }
[JsonProperty(OidcConstants.ClientMetadata.LogoUri)]
[Url]
public string LogoUri { get; set; }
[JsonProperty(OidcConstants.ClientMetadata.GrantTypes)]
public IEnumerable<string> GrantTypes { get; set; }
[JsonProperty(OidcConstants.ClientMetadata.RedirectUris)]
public IEnumerable<string> RedirectUris { get; set; } = new List<string>();
public string Scope { get; set; } = "openid profile email";
}
} using IdentityModel;
using Newtonsoft.Json;
namespace Example.IdentityServer.Models
{
public class ClientRegistrationResponse : ClientRegistrationModel
{
[JsonProperty(OidcConstants.RegistrationResponse.ClientId)]
public string ClientId { get; set; }
[JsonProperty(OidcConstants.RegistrationResponse.ClientSecret)]
public string ClientSecret { get; set; }
}
} |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Are there any patterns or best practices for registering new ApiResources and their scopes with IdentityServer? In our environment, we have multiple APIs (Resource Servers) which we would like to keep decoupled from our Identity Server implementation. Each of those APIs would need to somehow register themselves with Identity Server. This could possibly happen on deployment or on startup. We've seen the API Client Registration specification here. We will also need to do something like this as well for our internal API Clients. What would you recommend as a secure way of registering these? Are you planning on releasing any new endpoints to handle either of these?
The text was updated successfully, but these errors were encountered: