Update user profile through api without admin rights

Hi to all!
I’m new to keycloak and I’m looking for possibilities to update user profile info by api request without admin rights (and without direct using of account resource). Can you advice is it possible to do and how?

Details
I have project with some microservice architecture. I try to create facade service in front of keycloak to get access to user info through it. At first this facade must only redirect requests to keycloak, and later it must get functions of persisting and getting user profile by using self database - to reduce load on keycloak service from extra requests and add some business functions to it. Main idea is to use user rights which comes with request, and not to be “generator of the rights” like admin or something else.

I came across AccountRestService class - it represent api
wich I wanted to see - It uses AccountRoles, which can be added to any auth client. But I can’t get direct access to methods from
Postman request with token, even from account client (I switch on direct access and etc for account client).

Logically it seems to me that access token is sufficient rights to change the profile and I see AccountRestService - it looks like I missing some very little thing.

2 Likes

A working example of an Auth Service that supports microservices authorization: piggymetrics

The Admin REST API

Authenticating

export ACCESS_TOKEN=$(curl -X POST 'http://localhost:10001/auth/realms/master/protocol/openid-connect/token' \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=admin" \
  -d 'password=secret' \
  -d 'grant_type=password' \
  -d 'client_id=admin-cli' | jq -r '.access_token')

Note: I set the admin-cli Access Type to confidential .

Basic Operations

GET /{realm}/users

curl -X GET 'http://localhost:10001/auth/admin/realms/development/users' \
  -H "Accept: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq .

Output:

{
  "id": "35129fce-98de-47e6-85cc-cdb81b46c0d2",
  "createdTimestamp": 1578541188081,
  "username": "rob.ferguson",
  "enabled": true,
  "totp": false,
  "emailVerified": false,
  "firstName": "Rob",
  "lastName": "Ferguson",
  "email": "rob.ferguson@robferguson.org",
  "federationLink": "b02e5323-0ea4-442c-ba59-5e997d0c5f94",
  "attributes": {
    "LDAP_ENTRY_DN": [
      "uid=rob.ferguson,ou=users,dc=flowable,dc=org"
    ],
    "LDAP_ID": [
      "rob.ferguson"
    ],
    "modifyTimestamp": [
      "20200109033948Z"
    ],
    "createTimestamp": [
      "20200109033948Z"
    ]
  },
  "disableableCredentialTypes": [],
  "requiredActions": [],
  "notBefore": 0,
  "access": {
    "manageGroupMembership": true,
    "view": true,
    "mapRoles": true,
    "impersonate": true,
    "manage": true
  }
}

Ref:

Thank you for the answer!

Piggimetrics is very nice example and I wanted to do something close to it account service.
But, as you mentioned - to receive current user it needed to do admin authorized admin-cli request.
But I want to deal with current user with it’s authorization flow and its rights, received from ui or server (in terms of piggimetrics). In piggimetrics it resolved with using of access by scope (getAccountByName and connected “current” method). It because account and auth services have api and trusts to each other by ‘server’ scope or by Principal from token from auth flow (wich I wanted). But I can’t find such api in keycloak, which can access update requests by user access token.

The Master realm has an admin Role:

Your KEYCLOAK_USER:

docker pull jboss/keycloak
docker run -d --name keycloak \
  -p 10001:8080 \
  -v ~/workspace/Robinyo/serendipity:/serendipity \
  -e KEYCLOAK_USER=admin \
  -e KEYCLOAK_PASSWORD=secret \
  jboss/keycloak

is assigned the admin Role:

The admin role is required when you use the Admin REST API.

Ref: Role required to manage user consents from REST API

Yes, it all is right, and currently I have created the account-service in this way.
But it cause necessary to keep raw admin password in configuration file (for java keyclak-admin-client).
And if it will be stolen some way all security failes because it give access to every user account.

In this approach, I am confused by the placement of administrator data in the configuration file unnecessarily. I assume that for the functions of the administrator, the admin ui can authorize the administrator under the admin-cli. In this case, his confidential data will not be saved in one place without encryption, but only his token. And it can access all admin functions through account-service in secured way.

Create a Client (Access Type: confidential) in the Master realm for your Auth Service to use
Create a User in the Master realm (and assign it the admin role) for your Auth Service to use.

Which version of Java are you using?

If you are using Java 8 then your Microservices can use Apache HttpClient to interact with Keycloak (and each other). If you are using Java 11 then your Microservices can use the new HttpClient to interact with Keycloak (and each other).

You have 3 methods to get secrets to an app inside a docker container . The first 2 involve docker configuration: https://devops.stackexchange.com/questions/3902/passing-secrets-to-a-docker-container

Ref:

1 Like

[quote = “Robinyo, post: 6, topic: 1457”]
Which version of Java are you using?
[/ quote]
I’m using 11 version of java and Spring Boot, WebClient for requests (currently for simplification I’m using keycliak-admin-client).

I think we a little did not understand each other.
May be I have wrong undersandig of some details.

For example I have 3 instances: keycloak - Auth Service, account-service, ui (with associated client ui-client to auth)

Scenario:
I’m a user, who wants to login and change my email, for example.

  1. I use my user account link.
  2. Happens redirect to auth page and I go though authorization code flow with result: ui have user token with authorities by ui-client.
  3. Then it redirects me to my user account view (not keycloak account resource).
    Here happens next:
    UI requests user info from account-service by some GET request with token.
    Account service check that user is authenticated, check “ui-client” scope and may be check it’s user role.
    Then receives from self database or do request to keycloak userinfo endpoint for some user profile info like email.
  4. I edit my profile, for example email and apply changes.
    Here take place flow similar to 3ed point. Except there is no endpoint with user access to update user info by user itself. I.e. i send post request to account service - it change some profile data in self database and need to do such thing with keycloak user data, wich using in authorization flow.

Suppose I’m using admin client with default admin to update user info.

To do this I need some configuration in account service.
Something like this:

    @Bean
    Keycloak Keycloak () {
        return Keycloak.getInstance (
                "http://host: port/auth",
                "master",
                "admin",
                "somePassword",
                "admin-cli"
        );
    }

And write some code to process post request in controller

@Autowired
private Keycloak keycloak;

           @PostMapping ("/ user")
            public ResponseEntity <Void> updateUser (@AuthenticationPrincipal Jwt jwt, @RequestBody User user) {
                if (jwt == null)
                    throw new ResponseStatusException (HttpStatus.BAD_REQUEST);
                UsersResource usersResource = keycloak.realm ("someRealm"). Users ();
                UserResource userResource = usersResource.get (jwt.getClaim ("sub"));
                UserRepresentation userRepresentation = userResource.toRepresentation ();
                if (user.getEmail ()! = null) {
                    userRepresentation.setEmail (user.getEmail ());
                }
                userResource.update (userRepresentation);
                // and some actions to database here etc
           }

Of Course response will contain some new user data etc.
It’s all works fine for me currently.

Account microservice will be built into container and register with some discovery service.

But if some not good man do clone of server hard drive - it can obtain containers, and confidential info from it (from code as mentioned in my example).
And first what I thought it not store any confidential info (and I thought it easiest way; store only ui-client secret, but it does not grant many rights without user credentials) - because all permissions would be granted by authorization code flow.

It’s good advice about docker, I’m not very familiar with it - and if there is some way to hide admin data i’ll become calm ;). I’ll read about it, thanks.

It is really sad that this topic was not responded. I also needed to edit a user’s data using its own user priviledges instead of an admin one. I thought it would be easier.

2 Likes