I'm using Springboot SAML2 to authenticate with ADFS and and now I'm getting following error.
NameID element must be present as part of the Subject in the Response message, please enable it in the IDP configuration
After some research I found Name ID is not defined in my ADFS custom claim rule.
I'm new to ADFS saml2 authentication and no any experience in ADFS configuration part.
This is the claim rule I'm using now. And I want to know how do I define the emailAddress as the Name ID
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn", "http://schemas.xmlsoap.org/claims/Group", "http://schemas.xmlsoap.org/claims/CommonName", "http://schemas.xmlsoap.org/claims/Title"), query = ";mail,sAMAccountName,displayName,userPrincipalName,department,telephoneNumber,title;{0}", param = c.Value);
Thanks in advance.
Related
I made a small spring boot project and I need the id token. When I try to open an endpoint what requires google login I can login and then see the result of the endpoint calling. My question is that how to get the ID token? Where it can be found? How to extract it?
I send the openid scope but no idea where is the id token can be found to put the name/email/whatever on the front page if I want to:
security.oauth2.resource.user-info-uri = https://www.googleapis.com/userinfo/v2/me
security.oauth2.client.client-id = clientid
security.oauth2.client.client-secret = clientsecret
security.oauth2.client.user-authorization-uri = https://accounts.google.com/o/oauth2/v2/auth
security.oauth2.client.access-token-uri = https://oauth2.googleapis.com/token
security.oauth2.client.scope = openid email profile
Thanks in advance.
I have a multi-tenant application (springboot keycloak adapter + spring security) secured by Keycloak. Given the multi-tenant nature of the project, I wrote a multi-client connector which works fine.
On the official Keycloak doc, it is recommended (for multi-tenant applications) to model each tenant as a new realm, but for me it works better to have multiple clients within the same same realm. This is due to following advantages:
Client scopes, groups and other configs can be shared
Users don't need to be duplicated on N different realms
SSO login works perfectly within same realm clients (by using bearer
services +CORS)
So, everything works fine except for 1 thing, my initial SSO access_token (which is then shared across all bearer-only services by means of CORS) is kind of big (it shows all the resources - tenants - and its roles within each resource/tenant).
I'd like to limit the size of the access_token, by means of using "scopes" to restrict the roles in the token to only those meaningful to the tenant where I'm logged in at that time. For this, I'm manually firing a Request to the auth server (outside of the standard functionality provided by springboot/spring security) with the goal of manually overwriting whatever access-token exists within my app, with the new one generated by my extra request.
My "new" token request looks similar to this:
SimpleKeycloakAccount currentUserAccount = (SimpleKeycloakAccount) auth.getDetails();
String authServerUrl = currentUserAccount.getKeycloakSecurityContext().getDeployment().getAuthServerBaseUrl();
String realm = currentUserAccount.getKeycloakSecurityContext().getDeployment().getRealm();
String resource = currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceName();
String refreshToken = currentUserAccount.getKeycloakSecurityContext().getRefreshToken();
String token = currentUserAccount.getKeycloakSecurityContext().getTokenString();
Http http = new Http( new Configuration(authServerUrl, realm, resource,
currentUserAccount.getKeycloakSecurityContext().getDeployment().getResourceCredentials()
, null),
(params, headers) -> {});
String url = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token";
AccessTokenResponse response = http.<AccessTokenResponse>post(url)
.authentication()
.client()
.form()
.param("grant_type", "refresh_token")
.param("refresh_token", refreshToken)
.param("client_id", resource)
.param("client_secret", "SOME_SECRET")
.param("scope", "SOME_SCOPE_TO_RESTRICT_ROLES")
.response()
.json(AccessTokenResponse.class)
.execute();
// :) - response.getToken() and response.getRefreshToken(), contain new successfully generated tokens
My question is, how can I force my-app to change/reset the standard access-token & refresh_token obtained by the usual means, with these "custom created" tokens? or is that possible at all?
Thx for any feedback!
Further Information
To clarify more, lets analyze the behavior of a typical springboot/spring security project integrated with Keycloak:
You protect your endpoints with "roles" via configurations (either on the application.properties, or on the SecurityContext)
You know that this Spring application talks in the back channel with the Keycloak authorization server, that's how you become the access_token (But all this is a black box for the developer, you only know a Principal was created, a Security Context, Credentials; etc - everything happens behind the curtains)
Considering those 2 points above, imagine that you use an Http library to basically request a new token towards the auth server token endpoint like in the code above (yes filtered by scopes and everything). So the situation now is that though you have created a valid access_token (and refresh_token); since they were created "manually" by firing a request towards the token endpoint, this new token hasn't been "incorporated" to the application because No new Principal has been created, no new security context has been generated, etc. In other words, to the springboot application this new token is non-existent.
What I'm trying to accomplish is to tell sprinboot/spring security: "Hey pal, I know you didn't generate this token yourself, but please accept it and behave as if you'd have created it".
I hope this clarifies the intent of my question.
You can revoke a token using org.springframework.security.oauth2.provider.token.ConsumerTokenServices#revokeToken method.
On the Autorization Server:
#Resource(name="tokenServices")
ConsumerTokenServices tokenServices;
#RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}")
#ResponseBody
public String revokeToken(#PathVariable String tokenId) {
tokenServices.revokeToken(tokenId);
return tokenId;
}
Of course, you'll have to secure this method since is a very sensitive one.
In the case that each tenant is a separate client you can just use keycloak's "Scope" mapping at each client. Just turn off Full Scope Allowed and your tokens will only contain the user's roles for that specific client (tenant).
"Scope Mappings" is a a non intuitive way of saying "Define what roles should go into the access token" :-)
When turned off the UI changes and you even can configure what other roles of other clients should additionally go into the access token.
Just to give some closure to this question:
No, there doesn't seem to be any elegant or intended way to force a manual token renewal by means of using springboot/spring security keycloak connector.
The Javascript connector can do this trivially like this:
// for creating your keycloak connector
var keycloak = Keycloak({
url: 'http://localhost:8080/auth',
realm: '[YOUR_REALM]',
clientId: '[YOUR_CLIENT]'
});
// for login in (change scopes list to change access capabilities)
var options = {
scope: [EMPTY_STRING_SEPARATED_LIST_OF_SCOPES] // <-- here specify valid scopes
};
keycloak.login(options); // <-- receive a new token with correctly processed scopes
Given how easy it is to do this with the Keycloak client JS adapter, and how obscure it is to do this with the springboot/spring security adapter, it follows following:
Security design seems intended to have 2 (Keycloak security) layers; the first is a front-facing public client (usually password protected), and the 2nd layer is composed of several bearer-only services which would ussually only accept acces-tokens. If for those bearer-only services you want to implement finner grained control via scopes, you achieve that trivially by using a javascript based Keycloak client (other connectors as explained won't deal nicely with the header modification necessary to deal with OAuth2 scopes).
I have IdentityServer with Membership Reboot and IdentityManager running on a remote server, I've used the Admin UI of IdentityManager to setup a user, and add roles & claims to said user.
I'm developing a WebApi/SPA project that will use the remote server for Auth. Using fiddler I can request a token from the IdentityManagner on the remote box and use this token to against the local WebApi where Authorization is required. If the token is valid the WebApi processes like normal, if the token is bogus I get a 401. Works great.
The problem is when I want additional information about the user none of the claims or identity information is coming across. I'm not sure if the problem is at the IdentityServer side, The WebApi side, or if I'm not doing something correctly when getting my token.
I didn't realize we needed put the claims in the Scope definition. Incase anyone else stumbles upon this I changed my scope to the following
var scopes = new List<Scope>
{
new Scope
{
Enabled = true,
Name = "publicApi",
Description = "Access to our public API",
Type = ScopeType.Resource,
IncludeAllClaimsForUser = true, //I'll filter this down later
}
};
scopes.AddRange(StandardScopes.All);
return scopes;
Further details can be found here
Most of the Google Management APIs seem to have been enabled for Service Accounts. For example, I can retrieve calendars like so:
string scope = Google.Apis.Calendar.v3.CalendarService.Scopes.Calendar.ToString().ToLower();
string scope_url = "https://www.googleapis.com/auth/" + scope;
string client_id = "999...#developer.gserviceaccount.com";
string key_file = #"\path\to\my-privatekey.p12";
string key_pass = "notasecret";
AuthorizationServerDescription desc = GoogleAuthenticationServer.Description;
X509Certificate2 key = new X509Certificate2(key_file, key_pass, X509KeyStorageFlags.Exportable);
AssertionFlowClient client = new AssertionFlowClient(desc, key) { ServiceAccountId = client_id, Scope = scope_url };
OAuth2Authenticator<AssertionFlowClient> auth = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);
CalendarService service = new CalendarService(auth);
var x = service.Calendars.Get("calendarID#mydomain.com").Fetch();
However, identical code on the GroupssettingsService returns a 503 - Server Not Available. Does that mean service accounts can't be used with that API?
In a possibly related issue, the scope of the Groups Settings Service seems to be apps.groups.settings but if you call
GroupssettingsService.Scopes.AppsGroupsSettings.ToString().ToLower();
...you get appsgroupssettings instead, without the embedded periods.
Is there another method to use service accounts for the GroupssettingsService? Or any information on the correct scope string?
Many thanks.
I found this thread, and the most important part of the docs after some time. Posting so others don't waste their time in the future.
Your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported. If your application uses Google Sign-In, some aspects of authorization are handled for you.
See the "About authorization protocols" section of the docs
Why do you need to use a service account for this? You can use regular OAuth 2.0 authorization flows to get an authorization token from a Google Apps super admin user and use that:
https://developers.google.com/accounts/docs/OAuth2InstalledApp
OAuth2ProtectedResourceFilter in org.springframework.security.oauth2.provider.filter:
Collection<String> resourceIds = auth.getClientAuthentication().getResourceIds();
if (resourceIds!=null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {
throw new InvalidTokenException("Invalid token does not contain resource id ("+resourceId+"): " + token);
}
I think it is not useful. What does this code check for?
Based on what I've gathered, it is the id of the resource service.
It becomes more clear when you consider separating your oauth token provider servlet and your resource servers for the purpose of api versioning. For example, say Client A (cA) has access to api1 and Client B (cB) has access to api2, you enforce this access by dictating in your resource server xml for api1 that its resource-id=api1 and then configure your client details for cA that they have resourceIds="api1", and likewise for [cB,api2].
This lets us protect api access and keep its protection declaration separate from, say, our client roles declaration.
It looks like it checks whether a client is authorized to view a particular resource. Not sure how the token variable is involved, it looks like there is some more relevant code that you have not shown.