Keycloak Client for ASP.NET Kernel

Is there an existing Keycloak client for Asp.net Core? I found the NuGet package for .net , but it does not work with Core. Do you have any idea how easy it is to integrate with this security server (or perhaps using any other alternatives)?

+6
source share
4 answers

I played a little with this today. The easiest way is to use the OpenId standard.

In Startup.cs, I used OpenIdConnect authentication:

public void Configure(...) { (...) app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme, AutomaticAuthenticate = true, CookieHttpOnly = true, CookieSecure = CookieSecurePolicy.SameAsRequest }); app.UseOpenIdConnectAuthentication(CreateKeycloakOpenIdConnectOptions());'(...) }' 

OpenIdConnectOptions Method:

 private OpenIdConnectOptions CreateKeycloakOpenIdConnectOptions() { var options = new OpenIdConnectOptions { AuthenticationScheme = "oidc", SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme, Authority = Configuration["Authentication:KeycloakAuthentication:ServerAddress"]+"/auth/realms/"+ Configuration["Authentication:KeycloakAuthentication:Realm"], RequireHttpsMetadata = false, //only in development PostLogoutRedirectUri = Configuration["Authentication:KeycloakAuthentication:PostLogoutRedirectUri"], ClientId = Configuration["Authentication:KeycloakAuthentication:ClientId"], ClientSecret = Configuration["Authentication:KeycloakAuthentication:ClientSecret"], ResponseType = OpenIdConnectResponseType.Code, GetClaimsFromUserInfoEndpoint = true, SaveTokens = true }; options.Scope.Add("openid"); return options; } 

In appsettings.json add the configuration for Keycloak:

 { (...), "Authentication": { "KeycloakAuthentication": { "ServerAddress": "http://localhost:8180", "Realm": "demo", "PostLogoutRedirectUri": "http://localhost:57630/", "ClientId": "KeycloakASPNETCore", "ClientSecret": "secret-get-it-in-keycloakConsole-client-credentials" } } } 

Keycloak client is configured as follows:

If I want to authorize a user by role, I do something like this:

Add authorization for claims in the ConfigureServices method:

 public void ConfigureServices(IServiceCollection services) { (...) services.AddAuthorization(options => { options.AddPolicy("Accounting", policy => policy.RequireClaim("member_of", "[accounting]")); //this claim value is an array. Any suggestions how to extract just single role? This still works. }); } 

I edited the get method in ValuesController (default web API template):

 [Authorize(Policy = "Accounting")] [Route("api/[controller]")] public class ValuesController : Controller { // GET api/values [HttpGet] public Dictionary<string,string> Get() { var userPrinciple = User as ClaimsPrincipal; var claims = new Dictionary<string, string>(); foreach (var claim in userPrinciple.Claims) { var key = claim.Type; var value = claim.Value; claims.Add(key, value); } return claims; } 

If I log in with a user who has an account role or is a member of a group that performs an account role, he should display my user statements at localhost: 57630 / api / values.

I hope this works for you.

Edit: .NET Core 2 Hello everyone! The way my application works has changed a bit, and I have not yet fully tested .NET Core 2, but you can still try connecting to Keycloak as follows in ConfigureServices:

  services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = Configuration["Authentication:KeycloakAuthentication:ServerAddress"] + "/auth/realms/" + Configuration["Authentication:KeycloakAuthentication:Realm"]; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidAudiences = new string[] { "curl", "financeApplication", "accountingApplication", "swagger"} }; options.RequireHttpsMetadata = false; //for test only! options.SaveToken = true; options.Validate(); }); 

And in Configure:

 app.UseAuthentication(); 

You can access your token later using IHttpContextAccessor httpContextAccessor, for example:

 public KeycloakAuthorizationRequirementHandler(IConfiguration config, IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache) { _config = config; _httpContextAccessor = httpContextAccessor; _memoryCache = memoryCache; } 

// get accessToken

 var accessToken = _httpContextAccessor.HttpContext.GetTokenAsync("access_token"); _httpContextAccessor.HttpContext.Items["username"] = username; 

Tell me how it goes.

+12
source

If you want to use standard .Net role mappings with Keycloak client roles, follow these steps:

Startup.cs:

  services.AddAuthorization(options => { options.AddPolicy("Users", policy => policy.RequireRole("Users")); }); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = Configuration["Authentication:oidc:Authority"] options.ClientId = Configuration["Authentication:oidc:ClientId"]; options.ClientSecret = Configuration["Authentication:oidc:ClientSecret"]; options.RequireHttpsMetadata = false; options.GetClaimsFromUserInfoEndpoint = true; options.SaveTokens = true; options.RemoteSignOutPath = "/SignOut"; options.SignedOutRedirectUri = "Redirect-here"; options.ResponseType = "code"; }); 

appsettings.json:

  "Authentication": { "oidc": { "Authority":"http://your-keycloak-server/auth/realms/your-realm", "ClientId":"Your-Client-Name", "ClientSecret":"Your-client-secret" } } 

Keycloak Client Settings:

Now you can use standard authorization role statements to apply Keycloak client roles to your ASP.NET project:

 [Authorize(Roles = "Users")] 
+2
source

What worked for us is to set these things in Startup.cs (this is cookie based authentication):

 public void Configure(...) { (...) app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme, AutomaticAuthenticate = true, CookieHttpOnly = true, CookieSecure = CookieSecurePolicy.SameAsRequest }); app.UseOpenIdConnectAuthentication(CreateOpenIdConnectOptions(_customConfig)); (...) } 

And setting parameters:

 private OpenIdConnectOptions CreateOpenIdConnectOptions(CustomConfigurationFile configuration) { var options = new OpenIdConnectOptions { AuthenticationScheme = "oidc", SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme, Authority = configuration.ServerAddress + "/auth/realms/" + configuration.Realm, RequireHttpsMetadata = true, PostLogoutRedirectUri = configuration.SystemAddress, ClientId = configuration.ClientId, ClientSecret = configuration.ClientSecret, ResponseType = OpenIdConnectResponseType.Code, GetClaimsFromUserInfoEndpoint = true, SaveTokens = true }; options.Scope.Clear(); options.Scope.Add("openid"); return options; } 
+1
source

I have exactly the same configuration as above, but I get:

  Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_grant', error_description: 'Code not valid', error_uri: 'error_uri is null'. 

this problem only occurs when the application is behind a reverse proxy, have any ideas?

0
source

Source: https://habr.com/ru/post/1262995/


All Articles