Keycloak : How to create custom rest api


Keycloak 

Custom rest api 
Get all user details without password/Token

 

Introduction:

Keycloak is an open source software product to allow single sign-on with Identity and Access Management aimed at modern applications and services.

Its developed by JBoss , A division of Red Hat and it can be use as free replacement for OAuth2.0 provider.

Keycloak comes with its own set of REST API’s as well we can add our own REST API’s by extending SPI features.

 

Service Provider Interfaces (SPI) –

SPI enables the customization of various aspects of server. Authentication flows, user federation providers, protocol mappers and many more.

 

Creating a REST API

In this article we will create REST API which will be served by keycloak server and provide all uses details without login.

 

To begin with let’s create plain java application with maven and the below dependencies to it.

Where keycloak.version is the version of keycloak server.

 

<dependencies>
    <dependency>
        <groupId>
org.keycloak</groupId>
        <artifactId>
keycloak-core</artifactId>
        <scope>
provided</scope>
        <version>
${keycloak.version}</version>
    </dependency>
    <dependency>
        <groupId>
org.keycloak</groupId>
        <artifactId>
keycloak-server-spi</artifactId>
        <scope>
provided</scope>
        <version>
${keycloak.version}</version>
    </dependency>
    <dependency>
        <groupId>
org.keycloak</groupId>
        <artifactId>
keycloak-server-spi-private</artifactId>
        <scope>
provided</scope>
        <version>
${keycloak.version}</version>
    </dependency>
    <dependency>
        <groupId>
org.keycloak</groupId>
        <artifactId>
keycloak-services</artifactId>
        <scope>
provided</scope>
        <version>
${keycloak.version}</version>
    </dependency>
</dependencies>

 

 

 

In maven project create below structure for resources

+--- pom.xml
+--- src
| +--- main
| | +--- java
| | | +--- gaurav
| | | | +--- keycloak
| | | | | +--- DemoRestProvider.java
| | | | | +--- DemoRestProviderFactory.java
| | +--- resources
| | | +--- META-INF
| | | | +--- jboss-deployment-structure.xml
| | | | +--- services
| | | | | +--- org.keycloak.services.resource.RealmResourceProviderFactor

Here we added DemoRestProviderFactory to create factory class for DemoRestProvider

Class DemoRestProviderFactory and DemoRestProvider will implement the interfaces org.keycloak.services.resource.RealmResourceProviderFactory and org.keycloak.services.resource.RealmResourceProvider respectively.

 

In Factory class DemoRestProviderFactory we will define the rest api end point name. say for demo its “gaurav-rest” and during constructor it will create instance for DemoRestProvider.

 

Please note factory instance will remain through out the lifecycle of keycloak server but DemoRestProvider instance will be created whenever we will hit the rest request for it.

 

Below is code for DemoRestProviderFactory

 

public class DemoRestProviderFactory implements RealmResourceProviderFactory{
  
public static final String ID = "gaurav-rest";

   public
RealmResourceProvider create(KeycloakSession session) {
     
return new DemoRestProvider(session);
  
}

  
public void init(Scope config) {}

  
public void postInit(KeycloakSessionFactory factory) {}

  
public void close() {}

  
public String getId() {    return ID;}

}

 

 

Now let update DemoRestProvider class with constructor to retrieves session from factory.

private final KeycloakSession session;
public
DemoRestProvider(KeycloakSession session) {        this.session = session;
}

 

And add method to return list of user details.

 


@GET
@Path("users")
@NoCache
@Produces({MediaType.APPLICATION_JSON})
@Encoded
public List<UserDetails> getUsers() {
List<UserModel> userModel = session.users()
.getUsers(session.getContext().getRealm());
return userModel.stream()
.map(e -> toUserDetail(e))
.collect(Collectors.toList());
}

 

 

Here UserDetails is custom class to store only username, first name, last name.

 

Now register the factory class to keycloak by adding factory class name to org.keycloak.services.resource.RealmResourceProviderFactory (as below file location)

 

| +--- resources
| | +--- META-INF
| | | +--- services
| | | | +--- org.keycloak.services.resource.RealmResourceProviderFactory
 

Deployment

Create the package by running maven build and copy it to keycloak deployment directory.

${KEYCLOAK_HOME}/standalone/deployments.

 

Keycloak support hot deployment so as soon file jar file copied to above location it will create <jar name>.deployed  file if deployment was successful and also add below in log file of keycloak.

 
06:26:10,212 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 1) WFLYSRV0016: Replaced deployment "keycloak-rest-api-1.0.jar" with deployment "keycloak-rest-api-1.0.jar"

 

Validation

 

If application was deployed correctly it will be added to keycloak server and visible under provider details as below.

Testing

 

Before testing we need to create realm and add few user to keycloak.

To create realm first login to keycloak server and create realm as below.

 


 

Here I create realm “GW” and added few users to it.

 

Now we have user we can execute the rest . Below is sample for curl command

 

curl  -s -X GET   "http://localhost:8180/auth/realms/GW/gaurav-rest/users" | jq
[
  {
    "userName": "gaurav",
    "firstName": "gaurav",
    "lastName": "wadhone"
  },
  {
    "userName": "testuser",
    "firstName": "test",
    "lastName": "user"
  },
  {
    "userName": "testuser2",
    "firstName": "test",
    "lastName": "user2"
  }
]

                             

 

Conclusion

 

Although this is bed example to retrieve user details without login/password but we can achieve same by extending SPI interface and we can use similar approach where Out of Box Admin API’s of keycloak are not enough.

 

We can also extend above example to execute with JWT token where user has specific role

 

Source

Source code : https://github.com/gauravwadhone/keycloak

 

 

 


No comments: