Keycloak Custom User Federation and Identity Provider Working Order - authentication

I have two custom authentication method on Keycloak.
One of them is custom implemented user federation. I configured it for X realm. System uses this implementation for login with username / password method. This implementation calls my federation service and it validates sent user. It works successfully and authenticates federated users.
Second one is an identity broking (openid connect). I configured a custom openid provider to Y realm. It works successfully and validates provider's users.
I configured both of them to same realm. When i try to use login with custom identity provider, authentication flow works correctly. In the end of flow, configured user federation (custom implemented user federation) triggers with username which comes from identity broking (custom identity provider) login process and it calls my federation service again.
When i try to login with identity providers, i do not want the user federation (custom implemented user federation) to work. It must work only when i try to login with username / password login.
How can i block working of user federation on this scenario?
Please share your experience.
Thanks

I had the same issue of the identity provider and custom user federation not both working at the same time. My solution wasn't to block user federation but to change my custom user federation code. The implementation of the method that returns the user from the UserLookupProvider interface (getUserByEmail/Username/Id) must be coded to return a AbstractUserAdapterFederatedStorage. This implementation of UserModel provides implementation for methods needed by keycloak to internalize users from identity providers. Additionally I implemented UserQueryProvider interface along with UserStorageProvider, UserLookupProvider, CredentialInputValidator to be able to see these users from the keycloak admin console.
From their documentation:
Keycloak comes with a helper class org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage that will delegate every single UserModel method except get/set of username to user federated storage.
...interface UserQueryProvider. If you do not implement this interface, then users will not be viewable in the admin console. You’ll still be able to login though.
Ref: https://www.keycloak.org/docs/latest/server_development/#_user-storage-spi
Code:
note: A custom keycloak user storage should have at least two classes. One main one that does the heavy lifting that must implement at least UserStorageProvider. And another that is a factory that calls this class. More on this on their Server Development guide. The following code goes in the main class (not the factory):
#Override
public UserModel getUserByUsername(String username, RealmModel realm) {
[...]
userModel = createUserModel(username, realm);
[...]
return userModel;
}
protected UserModel createUserModel( String username, RealmModel realm) {
return new AbstractUserAdapterFederatedStorage(session, realm, model) {
#Override
public String getUsername() {
return username;
}
#Override
public void setUsername(String username) {
//retrieves user through repository and sets the keycloak user to its username. (Seems redundant but works!)
usersService.getUserDetails(username).setUsername(username);
}
};
}

Related

Single sign-out in ASP.NET Core OpenID Connect

I have a number of applications that authenticate users through single sign-on (SSO) with Auth0. One of these is an ASP.NET Core MVC application, which uses the ASP.NET Core OpenID Connect (OIDC) middleware. The single sign-on works fine. For single sign-out from the current app, I'm calling Auth0's /v2/logout endpoint from the OnRedirectToIdentityProviderForSignOut event, per Auth0's quickstart example. However, I don't know how to configure the app to clear the local session when there is an SSO session sign-out from another app. Auth0 mentions:
Redirecting users to the logout endpoint does not cover the scenario where users need to be signed out of all of the applications they used. If you need to provide this functionality you will have to handle this in one of two ways:
Have short timeouts on your local session and redirect to Auth0 at short intervals to re-authenticate. This can be done by calling checkSession from the client which does this redirect in a hidden iFrame. If you take the hidden iFrame approach you need to be aware of rate limits and third-party cookie issues.
Handle this entirely at the application level by providing your applications a way to notify all other applications when a logout occurs.
I get the impression that the checkSession suggestion is intended for SPAs. How does the ASP.NET Core OpenID Connect middleware handle such SSO session sign-outs? Does it automatically re-authenticate with the authentication server at regular intervals? If so, how can this frequency be configured?
The AddOpenIDConnect middleware module have a dedicated URL that it listens on and that the external provider can call after it has signed out the user.
The URL is defined in the source here and looks like this:
SignedOutCallbackPath = new PathString("/signout-callback-oidc");
RemoteSignOutPath = new PathString("/signout-oidc");
/// <summary>
/// The request path within the application's base path where the user agent will be returned after sign out from the identity provider.
/// See post_logout_redirect_uri from http://openid.net/specs/openid-connect-session-1_0.html#RedirectionAfterLogout.
/// </summary>
public PathString SignedOutCallbackPath { get; set; }
/// <summary>
/// Requests received on this path will cause the handler to invoke SignOut using the SignOutScheme.
/// </summary>
public PathString RemoteSignOutPath { get; set; }
So you could try to configure Auth0 to call the RemoteSignOutPath then that could perhaps work for you. However if you many many clients, then you need to have a different strategy. Perhaps use shorter access-token lifetime?
I've accepted Tore's answer since it's the best approach when front-channel logout is supported by the OpenID identity provider. In my case, Auth0 doesn't support OpenID Connect front- or back-channel logout:
Other than when Auth0 is using SAML, Auth0 does not natively support Single Logout. Single Logout can be achieved by having each application check the active session after their tokens expire, or you can force log out by terminating your application sessions at the application level.
I managed to achieve this in ASP.NET Core MVC 3.1 by reducing the ExpireTimeSpan in the AddCookie configuration:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(/* ... */)
.AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
});
// ...
}
}
Consequently, any controller method decorated with [Authorize] would automatically re-authenticate with Auth0 every minute. If the Auth0 session is still active, the user would get immediately redirected to the target page. If not, they would be presented with the Auth0 login page.

Asp.Net Core: order of execution of IAuthorizationFilter and Authentication Service

I'm implementing both authentication and authorization mechanisms in Asp.Net Core Web Api application.
I use JWT for users authentication configured in:
ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(...).AddJwtBearer(...)
...
}
(similar to https://stackoverflow.com/a/45901894/1544054)
this service also populate HttpContext.User according to the JWT data.
For authorization I use a custom RBAC implementation, based on
class AccessControlFilter : IAuthorizationFilter
{
public AccessControlFilter(string permission) {...}
public void OnAuthorization (AuthorizationFilterContext context){...}
}
(similar to the great answer in https://stackoverflow.com/a/41348219)
I need to know for sure that my AccessControlFilter will run AFTER the JWT Authentication Service, so that the
context.HttpContext.User is already populated.
(I guess that the order is correct and filters will run after services, but I could not find the right documentation.)
From the ASP.NET Core Security Overview (emphasis mine):
Authentication vs. Authorization
Authentication is a process in which a user provides credentials that are then compared to those stored in an operating system, database, app or resource. If they match, users authenticate successfully, and can then perform actions that they're authorized for, during an authorization process. The authorization refers to the process that determines what a user is allowed to do.
Another way to think of authentication is to consider it as a way to enter a space, such as a server, database, app or resource, while authorization is which actions the user can perform to which objects inside that space (server, database, or app).
So to answer your question : authentication always occurs before the authorization pipeline. This makes sense, because you need to know who the user is before knowing what he's authorized to do.

OpenID Connect, redirect without login form if not already logged in?

In OpenID Connect, I would like my users to be automatically connected to my client if they are connected to the identity provider (given that they already authorized my client app).
Here is the workflow I want :
USER arrives on CLIENT homepage
USER is redirected to IdP (Authorization request)
If he's logged in IdP, he's redirected to CLIENT and OIDC workflow begins, then he's logged in CLIENT
If he's not logged in IdP or he did not authorize CLIENT to access his identity, the login form of IdP is NOT displayed to USER and he's redirected to CLIENT homepage, not logged in
It would be like "Gateway" mode in CAS.
I use Authorization Code Flow and I don't want to use Javascript with Implicit Flow to login through JS dynamically.
Do you know if it is possible ? I can not find it in the spec.
Thanks :)
You are considering SSO behaviour on-top of IDP. This is usually outside OpenID Connect specification and usually bound to specific identity provider you are using (ex:- Azure, PING or WSO2). But there are some parameters to tweak the this behaviour such as prompt and login_hint which are optional.
From OpenID Connect authentication request section
prompt
Space delimited, case sensitive list of ASCII string values that
specifies whether the Authorization Server prompts the End-User for
reauthentication and consent.
Valid values are login, none, consent and select_account. You can use them to enforce force login or to allow a select account.
login_hint
Hint to the Authorization Server about the login
identifier the End-User might use to log in (if necessary)
One good example is enabling SSO behaviour by passing login_hint to identity provider. If identity provider can verify identity against (for example) a corporate LDAP and detect logged in state, you can give credential free login experience. At the same time, you may use prompt=login to enforce a login, even when identity provider hold a logged in session.
Alternatively, you can use signinSilent(). I have used it on my login page ngOnInit (since AuthGuard will anyway redirect the user to login, I thought it will be the perfect place in my scenario).
// login.ts
ngOnInit(): void {
this.authService.signinSilent().then(_ => {}).catch(_ => {});
}
// authService
public signinSilent() {
return this.userManager.signinSilent();
}
signinSilent method will return the user object if user already has a valid session with idp. else it will throw an error, probably login_required.

Restricting an api resource on user level in IdentityServer4

We want to set up a general authentication service, making use of IdentityServer4, where we define a set of users that can have access to one or more api's.
Users will be globally defined, but can only have access to specific api's.
Maybe I'm missing something, but this doesn't seem to be supported. If a user is authenticated and receives an access token, he can access all api's.
I've read the blog post https://leastprivilege.com/2016/12/16/identity-vs-permissions/ and I fully understand and agree that authorization should be handled in the client application itself, but this first level of checking if a user can access an api seems trivial to me.
I worked with Azure AD and ADAL before, and in Azure AD it is possible to define for an application (=resource in IdentityServer4 terminology) which users can access it. When requesting a token you specify the resource you want to access and if the user has no access to it, no access token is returned.
Can anyone tell me what is the proper way to set this up? Most of our applications are Angular SPA applications so we use the implicit flow.
I would suggest some high level idea you do it this way,
Authenticate users and make sure it returns with access_token and certian claim information
Define the authorization rules in your data store or somewhere you can read that can map the claims to permissions/attributes.
Now write a authorization logic or service where you can map the valid permissions from step 2 and seek for permissions.
This you keep your identity and authorization clean and separate and only update the rules on application as needed to map the general permissions
You scan set up different clients with access to different APIs the users just authenticate the client and they have access to that API. This isnt going to prevent user1 from authenticating to an api you dont want them accessing.
You can also set up user claims and policy to prevent different users from accessing different apis. Something like this would ensure that only users who are at least 21 years old would be able to access this api.
[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseController : Controller
{
public IActionResult Login() => View();
public IActionResult Logout() => View();
}
More info can be found here Custom policy-based authorization
The proper way is to either use Policy-based or Role-based authorization.
Identity server is doing the authentication (checking if the client is registered, if it is allowed to access the requested scopes, authenticates the user, and gives him claims) but it is up to your application (the client) to authorize the user (based on the roles in the claims, either allow or don't access to a certain method).
You have an option when authenticating against IDS to check the clientID and the user, and write some custom Profile Service where you can apply some rules and reject the user.

Client Credentials from within UserService on IdentityServer3

I need to connect to an external API to validate user credentials and get claims for user from within my custom UserService in IdSrvr, but using Client Credentials as if IdentityServer were a client to connect to another service.
What should be the approach?
First thing to come to my mind was to just make an HttpClient instance within UserService to connect to IdentityServer itself and make the request... But I don't know if there's a better/cleaner way.
The OwinEnviroment extensionmethods let you issue tokens.
public MyCustomUserService(OwinEnvironmentService owin)
{
_owin = owin;
}
public async Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
var token = await _owin.Environment.IssueClientToken(
clientId: "Banana",
scope: "resource1",
lifetime: 3600);
// call protected API with token
}
Link to GitHub issue with same question
There is a grant for this called the ResourceOwner Grant. Please read the spec accordingly.
The credentials should only be used when there is a high degree of
trust between the resource owner and the client (e.g., the client
is part of the device operating system or a highly privileged
application)
Most people would highly recommend that you do not use this grant as its an antipattern that requires the application to pass out user credentials which goes against the whole idea of OIDC. This grant is mostly here and used for legacy purposes.