I am learning Spring Security and can't understand what's the difference between authentication and principal. I do understand that the code below is not logically connected, but as far as I understand both authentication and principal gives us possibility to get the data from the currently logged user.
#PreFilter("filterObject.owner == authentication.name")
#PreAuthorize("hasRole('ADMIN') or principal.userId == #id")
Principal represents the logged in User. Spring's Authentication interface extends the Principal interface, so Authentication is a Principal.
Before the user has been authenticated, Authentication can represent the token for an authentication request.
After the user has been authenticated, it can provide extra information about the Principal e.g. through getAuthorities(..) you can get the authorities that the principal has been granted, after successful authentication.
Related
I am going through this api doc (source) of Spring OAuth2 ClientDetails Interface. And I am not sure how this i.e clientDetails.getAuthorities() works or helps in the authorization flow. The API docs describes it as below:
Collection<org.springframework.security.core.GrantedAuthority> getAuthorities()
Returns the authorities that are granted to the OAuth client. Cannot return null. Note that these are NOT the authorities that are granted to the user with an authorized access token. Instead, these authorities are inherent to the client itself.
Returns:
the authorities (never null)
And I understand the above is different from the userDetails.getAuthorities() of UserDetails Interface. The API docs says as below:
java.util.Collection<? extends GrantedAuthority> getAuthorities()
Returns the authorities granted to the user. Cannot return null.
Returns:
the authorities, sorted by natural key (never null)
I understand that, in ClientDetails we are dealing with granting permission to the OAuth2 Client, while in UserDetails we are granting the permission to User i.e Principal.
But how is the former different from later and when to use the former.
A little elaboration -
When dealing with OAuth, we are dealing with tokens issued by Auth Server. The tokens are typically jwt tokens with information about the authorities granted to the User. A typical base64 decoded token's payload might look like below:
{
"app-userId": "c54a-4140-9fa0-0f39",
"user_name": "abc#xyz.com",
"scope": [
"all"
],
"exp": 1656929583,
"authorities": [
"app1_viewer",
"app1_modifier",
"app2_viewer",
"app2_blog_creator],
"client_id": "client_A"
...
}
The authorities above are the authorities of the User who is logged-in and using the app.
When the user accesses app1 - it checks the above jwt token to make sure the user has the required permissions/authorities.
If app1 has to call app2, then app1 passes the above jwt which is specific to current user (as Authorization header) to app2. App2 processes this jwt token received in headers and checks if the user has permissions to access/edit the resource. And returns 200 or 403 accordingly.
As you can see, the process is dealing with userDetails.getAuthorities(). So, how and where or in which case does clientDetails.getAuthorities() help. What are the use cases/examples of it.
Could some one explain. Thanks for any answers.
I am not a Java hero, but I work a lot with Azure and Oauth2. Your question got me thinking what that could be. From what I learned is that Authorities decide who gets a valid token and who doesn't (token issuer). From the Microsoft Azure documentation about MSAL I got the following:
Authority
The authority is a URL that indicates a directory that MSAL can
request tokens from.
Common authorities are:
https://login.microsoftonline.com/TENANT/
Sign in users of a
specific organization only. The in the URL is the tenant ID
of the Azure Active Directory (Azure AD) tenant (a GUID), or its
tenant domain.
https://login.microsoftonline.com/common/ Sign in users
with work and school accounts or personal Microsoft accounts.
https://login.microsoftonline.com/organizations/ Sign in users with
work and school accounts.
https://login.microsoftonline.com/consumers/ Sign in users with
personal Microsoft accounts (MSA) only.
A valid use case could be that one wants to build a multi-tenant application. So users from multiple authorities are able to sign-up and sign-in to your application. On basis of the authority you can filter which data a user can see, only data from the users' organization for example. Basically the same idea as how you would use the application roles from userDetails.getAuthorities() to restrict what a user can see or do according to his role within that specific application.
I have:
Spring boot client application with some public endpoints and private endpoints which require #PreAuthorize("#oauth2.hasScope('resource.read')") for example
I have a external authorization server: Cloudfoundry UAA
I have a external OIDC provider linked to UAA I can use that to authenticate a person, I receive a Person_ID from the ID_Token from that external OIDC provider
Now I need to change UAA core code to implement my logic of using that Person_ID and searching for equivalent user from LDAP which shares the same Person_ID and then I will need to add it's usergroups to the token for the client. (I have done it currently in the /userinfo endpoint)
So I have done this logic in the /userinfo endpoint, when client receives a access token (From client, redirected to UAA, from UAA to OIDC for AUTH, then back again for the token and then this token is sent to client, now client can take the token and ask for the /userinfo which will then have it's user roles)
Is this bad logic? Should I add the LDAP implementation(step4) inside the access token already somehow?
Really, as is often the case with design questions, it depends.
The key to remember is that OIDC and its associated id_token are for authentication. It's common for the /userinfo response to state claims about who the user is. Part of the user's identity might be their role.
OAuth and its associated access_token, on the other hand, are for authorization. It's common for the access token to state claims about what the client is authorized to do. What a client might be able to do may be different than the user's role.
Think about what decisions this client will need to make. It may be able to make choices like which of its pages it can show, based on the roles that it inferred from the /userinfo response.
Think about what this client will communicate with. Maybe it will communicate with a resource server. If the client passes the access_token obtained during login, then that token should indicate what the client is authorized to do.
How do i get access to the currently authenticated users access token in a Keycloak Service Provider Interface when the user has just logged in?
Current situation:
I am doing a manual Password Grant with Apache HttpClient inside a custom User Federation/Storage Provider when the user is performing a login with username and password.
The users access token is then used to call an internal API with his authentication context. This API call with the users bearer token is required for auditing/GDPR purposes since the user gives multiple consents when logging in.
I am assuming there is no way to get the current users authentication context within a user storage provider since the user is not yet authenticated at that point in time, right?
Is password grant the correct way to obtain a user auth context/token at that time? Another option might be to chain SPIs, e.g. use an Authentication SPI and intercept the token there. But it seems you cannot overwrite an existing Auth flow.
The last and maybe best option would be to create an Event Listener Provider. But do i have access to the access token there?
I would really appreciate some input because this whole endeavour feels a bit off.
Another option (which makes more sense for me) would be to use a client id to authenticate as a service (client authentication), in order to perform the auditing. That way you don't even need the user to be authenticated at that point. I see it as a better solution, since, apart what I have said, auditing is actually a system related chore. If you let any user do auditing, they could script some code with a valid token to perform massive/fake auditings by their own.
It makes more sense to leave it to a concrete client, with a concrete role and request that role for the auditing process.
I am confused about the use of OAuth 2.0 as an Authorization method and OpenID Connect as an Authentication method.
Based on my knowledge OAuth 2.0 is only an Authorization method. In other words, this is the process to request an ACCESS_TOKEN and RECEIVE this ACCESS_TOKEN, like depicted in the image below in yellow ellipse: (simplified)
Before an OAuth 2.0 Client retrieves an ACCESS_TOKEN from an Authorization Server this Server should verify if the User allows it and this is an Authentication Process that OAuth 2.0 does not care about.
When OpenID Connect is included in the mix it allows for an Authentication Method as well, but in my knowledge OpenID Connect just adds a "Claim" in the JWT Token that holds information about user that is using the service, like: email, name and others.
My questions are:
Why not ignore OpenID Connect and just add more "claims" in OAuth
2.0 to get information about users?
Is my description of the flows correct?
OpenID Connect does not merely "add a claim in JWT Token" but:
it introduces a completely new token (id_token) with radically different
semantics than the OAuth 2.0 access_token and a standardized format that is understood by the Client as opposed to the access_token which is opaque to the Client
it "twists" the role of the Client, now becoming the "audience" (or: intended recipient) of a token (i.e. the id_token) whilst the audience of the access_token is still a remote entity (aka. Resource Server) and the Client is only the "presenter" of the latter
The 2nd item is the primary source of confusion between OAuth 2.0 and OpenID Connect.
I don't know if your method will work or not but you're totally free to roll your own authentication. After all, that's what Facebook, GitHub and many others did by customizing oauth2. There ended up being so many oauth2 "authentication" methods that it was never plug and play if you wanted to change your provider. I believe that's why OpenID connect was introduced--a common way of connecting and reasoning about authentication while building on the established oauth2 pattern for authorization. Use OpenID connect or don't...but if you don't you'll be reinventing the wheel.
#sdoxee answers explains thing correctly. But I am adding bit more information for OP's understanding.
These days many identity providers (eg:- Azure AD) issue JWT based access tokens. These JWT access tokens do contain claims about end user as well as JWT related validation details (eg:- Token expiration). Here is the link for Azure AD OAuth 2 success response which highlights access token to be a JWT. Also, see JWT claims to see how they explain the claims. Samples are given below,
family_name : User’s last name or surname. The application can display this value.
given_name : User’s first name. The application can display this value.
One could think of building authentication on claims present in access token, but this is not sticking with protocol. And mostly claims and user information will be implementer specific. Also, by protocol definition, these two tokens (id and access) have two different audiences.
ID token is for client, for validation and for authentication.
Access token is for OAuth 2 protected endpoint.
Again, as #sdoxee highlight, use the correct protocol at correct place. Having claims in access token does not necessarily mean you should use them for authentication.
i am using Spring SAML2.O and WSO2IS::
After successfully authentication in IDP its send a saml assertion(carry all the information of the User like username, roles and etc.) as part of response to service provider.
Here what i want is, i want to authorized the user on the basis of ROLES. SO how can i fetch the role of the user from saml assertion and authorized and give the access permission into my service provider.
here is my SAML Assertion:-
Your help is going to save me.
thanks in advance
If want to do authorization through WSO2IS, it's already baked in, though there are a couple ways to approach it depending on your needs. As a general answer, you probably want to review Post Authentication Handlers.
You don't necessarily need to write your own handler though. You mentioned wanting to read the role from a SAML assertion, but if you just want to do basic authorization by role, why not let WSO2 check it for you? You can apply an XACML policy by enabling authorization on the service provider under Local and Outbound Authentication in the IS.
If none of those options work for you, you can still manage authorization by using REST calls to the PDP.