Open EricNjue opened 6 years ago
can you please share the request you are sending to the identityserver ?
I've attached a sample file showing the various clients I've & a sample request done via postman
instead of grant_type : "password" , the grant_type should be "external" if you want to exchange external tokens with identityserver..
If I put external as the grant_type, would I not be limited to use just the external providers? I'm trying to achieve a solution whereby I can use both External providers (using this project) & also provision of users to create accounts within our app domain. For the external users, its working perfectly, but after adding a custom IProfileService implementation, even the external grant_type stops working and throws invalid_grant. What could be the issue?
Let me test it at my end , I will come back to you with further updates regarding your issue..
any advances on this? i have the same scenario as @EricNjue and i didnt find any way around yet
@EricNjue @romulotil
Sorry for my late reply , I have been busy in other stuff.
I have made a few changes to my CustomProfileService
so that I could use both the "external" grant_type and "password" grant..
below is the code for my updated 'CustomProfileService".. What I am doing in it is , I have two different stores (one for external users and the other for the app users), so based on the 'subject' I try to find the user in either of the stores.. If found one the I send the user claims in the context..
` public class MyCustomProfileService : IProfileService { private readonly IExternalUserStore _externalUserStore; private readonly TestUserStore _testUserStore;
public MyCustomProfileService(IExternalUserStore externalUserStore,TestUserStore testUserStore)
{
_externalUserStore = externalUserStore;
_testUserStore = testUserStore;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = _testUserStore.FindBySubjectId(context.Subject.GetSubjectId());
if(user != null)
{
context.AddRequestedClaims(user.Claims);
}
else if (await _externalUserStore.FindByIdAsync(context.Subject.GetSubjectId()) != null)
{
var claims = await _externalUserStore.GetUserClaimsByIdAsync(context.Subject.GetSubjectId());
context.AddRequestedClaims(claims);
}
}
public Task IsActiveAsync(IsActiveContext context)
{
// var subjectid = await _externalUserStore.FindByIdAsync(context.Subject.GetSubjectId());
context.IsActive = true;
return Task.CompletedTask;
}
}`
@EricNjue You can add additional claims in your custom Profile Service..
@waqaskhan540 thanks for replying... It was very helpful
I changed the TestUserStore with the UserStore from EF I am using and now it's working fine.
@romulotil Cheers..
@romulotil How did you achieve changing the TestUserStore with the UserStore from EF? @waqaskhan540 any advice?
@adamdsouza1
If you are using Identity then you can simply replace TestUserStore with UserManager..
@waqaskhan540
I am getting the following exception. Could you point me in the right direction?
System.InvalidOperationException: Unable to resolve service for type 'IdentityServer.External.TokenExchange.Interfaces.IExternalUserStore' while attempting to activate 'QuickApp.Pro.Authorization.ProfileService'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func
2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at IdentityServer4.Hosting.EndpointRouter.GetEndpointHandler(Endpoint endpoint, HttpContext context) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\EndpointRouter.cs:line 52
at IdentityServer4.Hosting.EndpointRouter.Find(HttpContext context) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\EndpointRouter.cs:line 39
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\IdentityServerMiddleware.cs:line 49
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\IdentityServerMiddleware.cs:line 69
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\BaseUrlMiddleware.cs:line 36
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
The implementation of the custom ProfileService is as follows
public class ProfileService : IProfileService
{
private readonly UserManager
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
if (user != null)
{
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
if (user.JobTitle != null)
claims.Add(new Claim(PropertyConstants.JobTitle, user.JobTitle));
if (user.FullName != null)
claims.Add(new Claim(PropertyConstants.FullName, user.FullName));
if (user.Configuration != null)
claims.Add(new Claim(PropertyConstants.Configuration, user.Configuration));
context.IssuedClaims = claims;
}
else if (await _externalUserStore.FindByIdAsync(sub) != null)
{
var claims = await _externalUserStore.GetUserClaimsByIdAsync(sub);
context.AddRequestedClaims(claims);
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
if (user != null)
{
context.IsActive = (user != null) && user.IsEnabled;
}
else if (await _externalUserStore.FindByIdAsync(sub) != null)
{
context.IsActive = true;
}
}
}
@adamdsouza1
I think you need to bind your ProfileService in the DependencyInjection..
services.AddScoped<IProfileService,ProfileService>();
How would one add a custom IProfileService service provider to the existing app? Am looking into ways I can integrate local account creation in combination with social login providers.
The issue am experiencing is that, after adding a custom IProfileService, am getting an "invalid_grant" response. Am using the below code
services.AddIdentityServer() .AddDeveloperSigningCredential() .AddAspNetIdentity<ApplicationUser>() //this adds the config data from DB (clients, resources) .AddConfigurationStore(options => { options.ConfigureDbContext = builder => builder.UseNpgsql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }) // this adds the operational data from DB (codes, tokens, consents) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseNpgsql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); // this enables automatic token cleanup. this is optional options.EnableTokenCleanup = true; options.TokenCleanupInterval = 30; }) .AddProfileService<ProfileServices>();
I also would like to add more claims to a user, how would one achieve that?