I am trying to create user with keycloak's /users endpoint in a spring boot project .
These are the steps I have followed
First created an admin in master realm and admin-cli client.
Used that to get instance of keycloak for further operations.
return Keycloak.getInstance(
keycloakProperties.getAuthServerUrl(),
"master",
adminConfig.getUserName(),
adminConfig.getPassword(),
"admin-cli");
I am able to get the user created if I don't add the client representation in user.
If I add the CredentialRepresentation inside the userRepresentation object ,I am getting the BadRequest error (400 code) without any details . I looked up the keycloak server logs that too wasnt helpful.
As a try,I did the user creation first and reset password later,then also user created,but unable to set password with reset-password endpoint (same error) .As mentioned in the documents,I have set the enabled property of userRepresentation to true.
Keycloak version : 12.0.4 ,Spring boot version : 2.1.6.RELEASE
I tried to read the entity from the response received, but failed in that too.
Any help to figure out the issue will e appreciated.
// Code for usercreation
UserRepresentation userRepresentation = new UserRepresentation();
userRepresentation.setUsername(userModel.getEmail());
userRepresentation.setEmail(userModel.getEmail());
userRepresentation.setCredentials(Arrays.asList(createPasswordCredentials(userModel.getPassword())));
userRepresentation.setEnabled(true);
Keycloak keycloak = getKeycloakInstance(keycloakProperties);
Response response = keycloak.realm(keycloakProperties.getRealm()).users().create(userRepresentation);
log.info("Response Code {}", response.getStatus());
Code for CredentialRepresentation :
private static CredentialRepresentation createPasswordCredentials(String password) {
CredentialRepresentation passwordCredentials = new CredentialRepresentation();
passwordCredentials.setTemporary(false);
passwordCredentials.setType(CredentialRepresentation.PASSWORD);
passwordCredentials.setValue(password);
return passwordCredentials;
}
I just want to update the real cause behind this issue,The server I used was of old version ,and the issue got fixed when tested against latest keycloak server.
Thank you for the support guys :)
Related
I created a spring boot service that is secured by the spring-security-keycloak-adapter. As the service already knows about the (keycloak) identity provider, I don't see any point in sending the issuerUrl and clientId to the mobile client to login directly into keycloak. Instead, I want to simply call the loginurl of the service in a webview on the client. In my understanding spring should redirect to keycloak and in the end return the token.
Unfortunately all flutter packages require the clientId and issuerUrl for the oauth process
I alread tried the openid_client package for flutter
As your can see in the following code example from the official repository it requires the clientId and issuerUrl
// import the io version
import 'package:openid_client/openid_client_io.dart';
authenticate(Uri uri, String clientId, List<String> scopes) async {
// create the client
var issuer = await Issuer.discover(uri);
var client = new Client(issuer, clientId);
// create an authenticator
var authenticator = new Authenticator(client,
scopes: scopes,
port: 4000);
// starts the authentication
var c = await authenticator.authorize(); // this will open a browser
// return the user info
return await c.getUserInfo();
}
Full disclosure: I didn't write Flutter, but I did write some of the related client code for Spring Security.
Why issuerUri? The reason for this is likely for OIDC Discovery. You can use the issuer to infer the other authorization server endpoints. This cuts down on configuration for you: You don't need to specify the token endpoint, the authorization endpoint, and on and on. If you supply only the issuer, then flutter figures out the rest.
Note that with Spring Security, this is just one configuration option among multiple, but something needs to be specified either way so the app knows where to go. I can't speak for flutter, but it may just be a matter of time before it supports more configuration modes.
Why clientId? This is a security measure and is required by the specification. If someone is calling my API, I want to know who it is. Additionally, authorization servers will use this client_id to do things like make sure that the redirect_uri in the /authorize request matches what is configured for that client_id.
I've been following Caroline's blog to setup a multi-user composer rest server. So, I have two servers viz. Admin Server and the User Server.
As mentioned in the tutorial I:
Started the Admin Server with no authentication and single user mode. I started this server with Admin's card.
Started the User Server with passport JWT authentication in multi-user mode. I started this server with Admin's card as well.
Created a User participant and generated a card for user from the admin server.
In this step I'm trying to exchange the JWT Token with the User Server(#2) and I'm able to get the token as well.
Ping user server with JWT Token. This results in "Error: Authorization Required".
I've followed Chris Ganga's blog for implementing JWT. My COMPOSER_PROVIDERS is:
COMPOSER_PROVIDERS='{
"jwt": {
"provider": "jwt",
"module": "/home/composer/node_modules/custom-jwt.js",
"secretOrKey": "somesecretkey",
"authScheme": "saml",
"successRedirect": "/",
"failureRedirect":"/"
}
}'
I'm exchanging JWT token for the first time from a Java service. To create a bearer token, I've written the following code:
public static String getBearerToken(String username, String id) throws UnsupportedEncodingException {
return Jwts.builder()
.claim("timestamp", System.currentTimeMillis())
.claim("username", username)
.claim("id", id)
.signWith(
SignatureAlgorithm.HS256,
"somesecretkey".getBytes("UTF-8")
).compact();
}
With this, I'm able to get the token. Next, I use this token to import the card into the wallet on User server:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set("X-Access-Token",getAccess_token(participantEmail));
headers.set("x-api-key", userServerKey);
LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("card", new FileSystemResource(card));
params.add("name", participantEmail);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(CARD_IMPORT_URL);
ResponseEntity<String> responseEntity = restTemplate.exchange(builder.build().encode().toUri(),
HttpMethod.POST, requestEntity, String.class);
However, this results in:
Unhandled error for request POST /api/Wallet/import: Error: Authorization Required
Finding 1
Generally, when we exchange the JWT for the first time using auth bearer, a db named "test" is created in mongo. This db contains three collections: accessToken, user and userIdentity. However, in my case when I exchange the token, no db is created in mongo. Any suggestions on how I can debug this?
Note:
This whole setup was working perfectly fine until I decided to prune and restart the network from scratch.
The issue here was I was using the same name for mongodb container across all the hosts. And since all the containers connect to the swarm network, there were 8 mongodb containers with the same name which is quite a silly mistake. It caused an issue when the docker container of composer-rest-server tried to connect to the mongodb container. This connection is defined in COMPOSER_DATASOURCES variable. Using the different name for each of the mongo containers across all the hosts solved this issue.
First of all I'm using
keycloak-authz-client-3.3.0.Final
spring boot 1.5.8.RELEASE
spring-boot-starter-security
I've been playing with Keycloak spring adapter exploring the examples since we want to adopt it to our project.
I was able to make it run for Roles easily using this tutorial:
https://dzone.com/articles/easily-secure-your-spring-boot-applications-with-k
After that I moved to permissions and that's when it gets trickier (that's also our main goal).
I want to achieve something like described in here (9.1.2):
http://www.keycloak.org/docs/2.4/authorization_services_guide/topics/enforcer/authorization-context.html#
To get permissions you need to setup in Keycloak Authorization, credentials, and then create Resources or Scopes and Policies to be able to create permissions (it took me a while but I got it working). Testing in the Evaluater everything seems fine.
Next step was to get user permissions on the Spring side. In order to do that I had to enable:
keycloak.policy-enforcer-config.enforcement-mode=permissive
The moment I enable this I get everytime this exception
java.lang.RuntimeException: Could not find resource.
at org.keycloak.authorization.client.resource.ProtectedResource.findAll(ProtectedResource.java:88)
at org.keycloak.adapters.authorization.PolicyEnforcer.configureAllPathsForResourceServer...
...
Caused by: org.keycloak.authorization.client.util.HttpResponseException:
Unexpected response from server: 403 / Forbidden
No matter what address I hit in the server.
So I started to investigate what was the root of the problem. Looking at some examples how to manually get the permissions I actually got them in postman with the following request:
http://localhost:8080/auth/realms/${myKeycloakRealm}/authz/entitlement/${MyKeycloakClient}
including the header Authorization : bearer ${accessToken}
response was {"rpt": ${jwt token}} that actually contains the permissions
So knowing this was working it must be something wrong with the Spring adapter. Investigating a bit further on the Keycloak exception I found that that error was occurring the moment the adapter was getting all the resources. For that it was using the following url:
http://localhost:28080/auth/realms/license/authz/protection/resource_set
with a different token in the headers (that I copied when debugging)
So when I tried it in postman I also got a 403 error, but with a json body:
{
"error": "invalid_scope",
"error_description": "Requires uma_protection scope."
}
I've enabled and disabled all uma configuration within keycloak and I can't make it work. Can please someone point me into the right direction?
Update
I've now updated Keycloak adapter to 3.4.0.final and I'm getting the following error in the UI:
Mon Nov 20 10:09:21 GMT 2017
There was an unexpected error (type=Internal Server Error, status=500).
Could not find resource. Server message: {"error":"invalid_scope","error_description":"Requires uma_protection scope."}
(Pretty much the same I was getting in the postman request)
I've also printed all the user roles to make sure the uma_protection role is there, and it is.
Another thing I did was to disable spring security role prefix to make sure it wasn't a mismatch on the role.
Update 2
Was able to resolve the 403 issue (you can see it in the response below).
Still getting problems obtaining KeycloakSecurityContext from the HttpServletRequest
Update 3
Was able to get KeycloakSecurityContext like this:
Principal principal = servletRequest.getUserPrincipal();
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) principal;
OidcKeycloakAccount auth = token.getAccount();
KeycloakSecurityContext keycloakSecurityContext = auth.getKeycloakSecurityContext();
AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
The problem now is that the AuthorizationContext is always null.
I've managed to get it working by adding uma_protection role to the Service Account Roles tab in Keycloak client configuration
More information about it here:
http://www.keycloak.org/docs/2.0/authorization_services_guide/topics/service/protection/whatis-obtain-pat.html
Second part of the solution:
It's mandatory to have the security constrains in place even if they don't mean much to you. Example:
keycloak.securityConstraints[0].authRoles[0] = ROLE1
keycloak.securityConstraints[0].securityCollections[0].name = protected
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /*
Useful demos:
https://github.com/keycloak/keycloak-quickstarts
This code works for me:
HttpServletRequest request = ...; // obtain javax.servlet.http.HttpServletRequest
Principal userPrincipal = request.getUserPrincipal();
KeycloakPrincipal < KeycloakSecurityContext > keycloakPrincipal =
(KeycloakPrincipal < KeycloakSecurityContext > ) userPrincipal;
KeycloakSecurityContext securityContext =
keycloakPrincipal.getKeycloakSecurityContext();
If you faced "java.lang.RuntimeException: Could not find resource" error and you are using Keycloak docker container, The error can be because of this. I dont have enough information about docker. Hence I download keycloak as a zip file and run it. It works properly.
Hi Stackoverflow team,
I am facing an issue in my REST Call which I am clueless about after trying to dig into the HTTP errors.
Somehow the authorization isn't working , eventhough the generation and fetch of the JWT token is successful.
Short Description of what I have in my Springboot App :
(Available for analysis of the problem at)
https://github.com/vivdso/SpringAuthentication
A DbRepository call that talks to a backend MongoDb collection named UserAccounts which has roles and credential details stored including the passwords (Ciphertexts).
A JWT token generation mechanism that returns a token which has to be attached to the HTTP Headers for the subsequent API Calls.
The flow in short.
".....:8080/auth" method post Content-Type appliction/json body:{"username":"user","password":"sample"} Response should be a jwt token
and then
Try the autheticated url .....:8080/order.
****EXPECTED RESULT : Header" Authorization:{$jwtToken from step 6} Actual Result: :( Error : 403 forbidden, this should be fully authenticated and should let the user access this api. Expected Result: "Hello here is my order"****
This is just a simple application with not too many details to worry about.
Any help will be appreciated.
Thanks in advance.
in your code I couldn't find the filter registration.
Try to add it in the WebSecurityConfig.java
#Bean
public CustomAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
CustomAuthenticationTokenFilter authenticationTokenFilter = new CustomAuthenticationTokenFilter ();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
and then register it with
http
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
inside the configuration method
et me know
This was a role mismatch issue. Was not matching with the role in jwt.
Changed the code to correct the role and it worked fine -
public CustomDbRepository(){
List<String> roles = new ArrayList<>(1);
//roles.add("ROLE_USER");
roles.add("USER");
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