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

 

 

 


Deployment with Helm Charts

Deployment with Helm



Helm is a package manager for Kubernetes same as yum/rpm for RHEL.

Helm has below capabilities :-

  • Install software.
  • Automatically install software dependencies.
  • Upgrade software.
  • Configure software deployments.
  • Fetch software packages from repositories.


It has two binary : helm and tiller

  • HELM is client which can create Helm chart as well install them. 
  • TILLER is server which runs inside the k8s cluster as pod.

TILLER

Tiller is server which runs as pod and mange helm installation

Installation 

Create new project (Or use existing ) for tiller project.
Download below YAML

https://github.com/openshift/origin/raw/master/examples/helm/tiller-template.yaml 

Set TILLER_NAMESPACE to project name and install tiller as below command.

oc process -f tiller-template.yaml -p TILLER_NAMESPACE="${TILLER_NAMESPACE}" -p HELM_VERSION=v2.14.2| oc create -f –

Add permission for deployment ( Tiller service account in Tiller installation must have the cluser-admin role) 

oc policy add-role-to-user edit "system:serviceaccount:${TILLER_NAMESPACE}:tiller"

To validate command is :-  

oc get sa

TILLER Repo


Tiller repo is location where all Helm packages are present. 
Few well known opensource example
  • ChartMuseum https://chartmuseum.com/ 
  • JFrog Artifactory https://www.jfrog.com/confluence/display/RTF/Helm+Chart+Repositories 
  • Git hub

Apart from repo can be set by using any local web server like apache web server / nginx

Configuration


For sample below we setup AHS 

Run helm as client only (No Internet access then use --skip-refresh and remove stable)
            helm init --client-only --skip-refresh
            helm repo remove stable 
# this will remove repo coming from https://kubernetes-charts.storage.googleapis.com. 

Install Apache and add the URL to HELM repo by below command.
           helm repo add gaurav http://gauravw:8080/

validate it as below
         helm repo list

Creating Helm Chart 

Helm usage Charts as packaging format
For creating chart run below command

helm create microserivce


This will create directory structure like below




charts/  :-       A directory containing any charts upon which this chart
templates/   : A directory of templates that, when combined with values,
  will generate valid Kubernetes manifest files.
Chart.yaml :- A YAML file containing information about the chart
values.yaml  :- The default configuration values for this chart  depends.



Chart.yaml

This file contains basic details for helm charts like chart name and version.

             cat microservice/Chart.yaml
                          apiVersion: v1  # Its always v1 (default same as yaml)
                          appVersion: "1.0“  # [Optional] for applicaton version
                          description: A Helm chart for Kubernetes  # Description of application
                          name: microservice   # Name of Chart.
                           version: 0.1.0  # Version of Chart. 

templates/  : Directory contain templates for all deployables.


It should be delete and created based on need.
            rm -f templates/*

By default it contains below files and should be deleted before creating own application
deployment.yaml  : Deplyments template with image and other details
_helpers.tpl  : for partial module
ingress.yaml  : Ingress template
NOTES.txt  : Notes
serviceaccount.yaml  : Create service account
               service.yaml  : Create service


Below is sample yaml file which can create tomcat pod while running command

On OpenShift : 
              oc create -f  tomcat-pod.yaml                     
On vanila Kuberenetes
             kubectl apply -f  tomcat-pod.yaml



Values.yaml


This file makes helm charts dynamic. On this file we set values for variables which can be used in templates. 
Below is sample where we replace values with variables.

as example we define .Values.image.name in values.yaml file as tomcat which replace while installation.



Packaging Helm Chart

To package run command 
                     helm package <Chart> 
Validation commands: 
                     helm lint <Chart>
                     helm inspect <Chart>
                     helm install --dry-run --debug <Chart>



Adding package to Helm Repo


Once package created simply copy file to repo 
For apache its under apache home (/var/www/html) 

And reindex the repo by running below command.
                     helm repo index  /var/www/html --url http://gauravw:8080/
And refresh repo to use them
             helm repo update


Installing Helm Chart.

Once package added to repo it can be installed by below command.
                      helm install microservice


This will install microsevice on K8s / openshift. 
                    
                    


Wildfly enable JMX

Wildfly JMX monitoring 


Wildfly is the new version of JBOSS and and for jboss 8 its code name was changed to wildfly and now any new release coming for Jboss after version 8 is coming with wildfly name

To  monitor performance via JMX console : like Jconsole/Visual VM we first need to create manangement user for wildfly.

Unlike conventional JMX configuration which uses rmi protocal Wildfly uses its own protocal http-remoting-jmx
While rmi protocal gives all the access to jndi wildfly gives the option to what should be access via JMX which makes JMX more secure.

How to create Wildfly management user 


To create user on Linux/Unix use the add-user.sh and on Windows use add-user-bat script file.

Its located under $JBOSS_HOME/bin where JBOSS_HOME is location where JBOSS/Wildfly is installed.

Whether you use bat / sh below steps would be same.






Once user is created find the client jar located under $JBOSS_HOME/bin/client/ and add to Jconsole path.
Wildfy also provide jconsole.sh / jconsole.bat located under $JBOSS_HOME/bin/

Executed it and it will open jconsole (look for classpath it's generated)
To check which classpath it generates enable the echo message at the end of jconsole script.

JMX url would be like below

service:jmx:http-remoting-jmx://<Hostname>:<JMX port>

By default JMX-port is 9990 (Unless it was not changed in standalone.xml or using offset)

In our example we run it on same machine and did not modify the port so our url is as below.

service:jmx:http-remoting-jmx://localhost:9990
On jconsole provide these details





Once logged in it will show details as below




Now here all monitoring details can be found like whatever mbeans are exposed are present on Mbeans secontion or VM summary.

Curl-HowTOs

Curl  : transfer data via simple url

An easy  alternative for below protocol
  1. FTP
  2. FTPS
  3. SCP
  4. SFTP
  5. TFTP
  6. DICT
  7. TELNET
  8. LDAP
  9. FILE
  10. HTTP
  11. HTTPS


No need to use any external software like Filezila or WINSCP for transfer data if curl is available.

Basic syntax of curl command

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>