Keycloak with java and reactJS

By April 27, 2020 May 18th, 2020 Blogs, Cloud

Written by Soumya. a, Software Developer at Powerupcloud Technologies.

In a common development environment we create login algorithms and maintain all the details in the project database.which can be a risk to maintain in huge application development and maintenance of all the client data and user information so we use a 3rd party software for maintaining login details to make the application more secure. Keycloak even helps in maintaining multiple applications with different / same users. 

Problem statement:

Local database can become a task to maintain login details and maintenance of it so we use 3rd party software like keycloak to make the application more secure 

How it works:

We add keycloak to the working environment and add required details of keycloak in code.and add application details in keycloak and run in the working environment.Detailed steps for local and server environments is in the Document.

Keycloak:

Keycloak is an open source Identity and Access Management solution aimed at modern applications and services. It makes easy to secure applications and services with little to no code.

Keycloak is used to add security to any application with the keycloak details added to the application it gives various options like a simple login ,login with username and password ,use of otp for login etc.

When we use keycloak we need not maintain login details in our database all the details are saved in the keycloak server and it is secure only the required details can be stored in our database.  

Different features of keycloak:

Users authenticate with Keycloak rather than individual applications. This means that your applications don’t have to deal with login forms, authenticating users, and storing users. Once logged-in to Keycloak, users don’t have to login again to access a different application.

This also applied to logout. Keycloak provides single-sign out, which means users only have to logout once to be logged-out of all applications that use Keycloak.

Kerberos bridge

If your users authenticate to workstations with Kerberos (LDAP or active directory) they can also be automatically authenticated to Keycloak without having to provide their username and password again after they log on to the workstation.

Identity Brokering and Social Login

Enabling login with social networks is easy to add through the admin console. It’s just a matter of selecting the social network you want to add. No code or changes to your application is required.

Keycloak can also authenticate users with existing OpenID Connect or SAML 2.0 Identity Providers. Again, this is just a matter of configuring the Identity Provider through the admin console.

User Federation

Keycloak has built-in support to connect to existing LDAP or Active Directory servers. You can also implement your own provider if you have users in other stores, such as a relational database.

Client Adapters

Keycloak Client Adapters makes it really easy to secure applications and services. We have adapters available for a number of platforms and programming languages, but if there’s not one available for your chosen platform don’t worry. Keycloak is built on standard protocols so you can use any OpenID Connect Resource Library or SAML 2.0 Service Provider library out there.

Gatekeeper

You can also opt to use a proxy to secure your applications which removes the need to modify your application at all.

Admin Console

Through the admin console administrators can centrally manage all aspects of the Keycloak server.

They can enable and disable various features. They can configure identity brokering and user federation.

They can create and manage applications and services, and define fine-grained authorization policies.

They can also manage users, including permissions and sessions.

Account Management Console

Through the account management console users can manage their own accounts. They can update the profile, change passwords, and setup two-factor authentication.

Users can also manage sessions as well as view history for the account.

If you’ve enabled social login or identity brokering users can also link their accounts with additional providers to allow them to authenticate to the same account with different identity providers.

Standard Protocols

Keycloak is based on standard protocols and provides support for OpenID Connect, OAuth 2.0, and SAML.

Authorization Services

If role-based authorization doesn’t cover your needs, Keycloak provides fine-grained authorization services as well. This allows you to manage permissions for all your services from the Keycloak admin console and gives you the power to define exactly the policies you need.

How to use:

In Local:

Prerequisites:

  1. Download keycloak
  2. Run keycloak in port 8085 (default keycloak port:8080)./standalone.sh -Djboss.socket.binding.port-offset=5
  3. Log in with master login which is registered while creating keycloak

In Server:

Prerequisites:

  1. Download java 
  2. Download keycloak using  wget
  3. Run keycloak in port 8085 (default keycloak port:8080)./standalone.sh -Djboss.socket.binding.port-offset=5
  4. Add ssl certificate for keycloak
  5. Log in with master login which is registered while creating keycloak

Steps for server :

Installation

Step 1: Login to the Linux server Step 2: Download Keycloak.

cd /opt/
wget https://downloads.jboss.org/keycloak/7.0.0/keycloak-7.0.0.tar.gz
tar -xvzf keycloak-7.0.0.tar.gz
mv keycloak-7.0.0.tar.gz keycloak

Step 3: Create a user to run keycloak application

adduser techrunnr
chown techrunnr.techrunnr -R /opt/keycloak

Step 4: switch the user to newly created user

sudo su - techrunnr

Step 5: Goto the keycloak home directory.

cd /opt/keycloak

Step 6: Execute the below command to make the application run on the reverse proxy.

./bin/jboss-cli.sh 'embed-server,/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)'
./bin/jboss-cli.sh 'embed-server,/socket-binding-group=standard-sockets/socket-binding=proxy-https:add(port=443)'
./bin/jboss-cli.sh 'embed-server,/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=redirect-socket,value=proxy-https)'

Step 7: Create a systemd configuration to start and stop keycloak using systemd.

cat > /etc/systemd/system/keycloak.service <<EOF
[Unit]
Description=Keycloak
After=network.target

[Service]
Type=idle
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/current/bin/standalone.sh -b 0.0.0.0
TimeoutStartSec=600
TimeoutStopSec=600

[Install]
WantedBy=multi-user.target
EOF

Step 8: Reload the systemd daemon and start Keycloak.

systemctl daemon-reload
systemctl enable keycloak
systemctl start keycloak

Step 9: Create an admin user using below command line.

./bin/add-user-keycloak.sh -u admin -p YOURPASS -r master

Configure Nginx reverse proxy

Step 1: Login to Nginx server and update in nginx.conf file.

upstream keycloak {
# Use IP Hash for session persistence
ip_hash;

# List of Keycloak servers
server 127.0.0.1:8080;
}

server {
listen 80;
server_name keycloak.domain.com;

# Redirect all HTTP to HTTPS
location / { 
return 301 https://\$server_name\$request_uri;
}
}

server {
listen 443 ssl http2;
server_name keycloak.domain.com;

ssl_certificate /etc/pki/tls/certs/my-cert.cer;
ssl_certificate_key /etc/pki/tls/private/my-key.key;
ssl_session_cache shared:SSL:1m;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://ke

Once it’s completed restart the Nginx server to take immediate effect. Now access the given URL to access the keycloak server and use the credentials which you created in Step 9.

Steps for both server and local:

1. Create a new realm:

To create a new realm, complete the following steps:

  1. Go to http://localhost:8085/auth/admin/ and log in to the Keycloak Admin Console using the account you created in Install and Boot.
  2. From the Master drop-down menu, click Add Realm. When you are logged in to the master realm this drop-down menu lists all existing realms.
  3. Type demo iin the Name field and click Create.

When the realm is created, the main admin console page opens. Notice the current realm is now set to demo. Switch between managing the master realm and the realm you just created by clicking entries in the Select realm drop-down menu.

2. Create new client:

To define and register the client in the Keycloak admin console, complete the following steps:

  1. In the top-left drop-down menu select and manage the demo realm. Click Clients in the left side menu to open the Clients page.

2. On the right side, click Create.

3. Complete the fields as shown here:

4. Click Save to create the client application entry.

5. Change Access type to confidential 

6. Click the Installation tab in the Keycloak admin console to obtain a configuration template.

7. Select Keycloak OIDC JSON to generate an JSON template. Copy the contents for use in the next section.

3. Role: 

Roles identify a type or category of user. Keycloak often assigns access and permissions to specific roles rather than individual users for fine-grained access control.

Keycloak offers three types of roles:

  • Realm-level roles are in the global namespace shared by all clients.
  • Client roles have basically a namespace dedicated to a client.
  • A composite role is a role that has one or more additional roles associated with it. 

3.1. Create new role 

Roles->Add Role->Role name and Description(admin_role)

3.2. To add manage user permission for the newly created role

enable composite roles->client roles–>realm management->manage users.

3.3. This step is used to add manage user permission for default roles

Roles->Default Roles->Client Roles–>realm management–> add manage users.

4. Adding created role permission to your client

Client->select your client->scope->realmroles->add created role(admin_role).

5. Add permission to a new realm from master realm

5.1. Master realm->client->select your client(demo-realm)–>roles->manage-users(default false make it as true)

5.2. For making it true : Enable composite roles–>client-roles–>select your client(demo-realm)–>add manage users

6. For adding manage user permission for client in master

Master->roles->default roles->client roles–>select ur client(demo-realm)–>add manage users.

7. Once the permissions are given the first user in the new realm should be created using which we can create multiple users from code(outside keycloak)

7.1.Select your realm(demo)–>Users->New user->details(add email id and name)->

7.2.Credentials(password)->

7.3.Role mappings->Client role->realm management->check if manage users is present else add

In React JS for connecting keycloak and adding authentication

Keycloak.js file

JSON file for adding keycloak server details(json from installation tab)

{
 "realm": "realm name",
 "auth-server-url": "keycloak url",
 "ssl-required": "external",
 "resource": "client name",
 "credentials": {
   "secret": "secret key"
 },
 "confidential-port": 0
}

Keycloak functions in app.js

These functions are used to connect to java method and authenticate the user

async Keycloakfunc() {
   const keycloak = Keycloak("/keycloak.json");
   console.log("keycloak");
   return keycloak
     .init({ onLoad: "login-required", promiseType: "native" })
 
     .then(authenticated => {
       if (authenticated) {
         if (sessionStorage.getItem("Loggined") == null) {
           return this.getUserId(keycloak.tokenParsed.preferred_username);
         } else {
           this.setState({ Loggined: true });
         }
       }
     });
 }
 
 async getUserId(user_name) {
   //alert(user_name);
   const endpoint = CURRENT_SERVER + "authenticateLogin";
   const bot_obj = {
     username: user_name
   };
   console.log(bot_obj);
 
   return axios.post(endpoint, bot_obj).then(res => {
     let data = res.data;
     if (data.status == "success") {
       //setting token locally to access through out the application
       sessionStorage.setItem("authorization", data.response.token);
       this.setState({ isAuth: "true" });
       console.log("login success");
       localStorage.setItem("userId", JSON.stringify(data.response));
 
       localStorage.setItem("userName", user_name);
       localStorage.setItem("rolename", data.response.roleid);
 
       this.setState({ Loggined: true });
       sessionStorage.setItem("Loggined", true);
     } else if (data.status == "failed") {
       console.log(data.response.error);
     }
   });
 }

In Java code:

Authenticake login service method:

This method is used to check if the username / email id is registered in our DB and authenticate for next steps 

@Service
public class LoginServices {

@Autowired
private UserMainRepo userMain;

@Autowired
private RoleUserPermissionRepo roleUserPermission;

@Autowired
private JwtTokenUtil jwtTokenUtil;

public String keyCloak(String object) {
System.out.println("LoginServices.keyCloak()");
String userId = null;
String roleid = null;
JSONObject responseJSON = new JSONObject();
JSONObject resultJSON = new JSONObject();

JSONObject obj = new JSONObject(object);
String username = (String) obj.get("username");

List<UserMain> authenticate = userMain.findByEmailId(username);

if (authenticate.isEmpty()) {
responseJSON.put("error", "user not found in DB");
resultJSON.put("status", "failed");
resultJSON.put("response", responseJSON);
} else {
List<RoleUserPermission> roleUserData = roleUserPermission.findByUserMainId(authenticate.get(0));
userId = roleUserData.get(0).getId();
roleid = roleUserData.get(0).getRoleMasterId().getId();

// Creating JWT token for security
JwtUserDetails userDetails = new JwtUserDetails();
userDetails.setUsername(username.trim());
final String token = jwtTokenUtil.generateToken(userDetails);
final String secretKey = "botzer";
String encryptedToken = AES.encrypt(token, secretKey);
responseJSON.put("token", encryptedToken);
responseJSON.put("userId", userId);
responseJSON.put("isLoggedIn", "true");
responseJSON.put("roleid", roleid);
resultJSON.put("status", "success");
resultJSON.put("response", responseJSON);
}
return resultJSON.toString();
}

User controller Method :

All the details for creating user such as email id username etc is passed from front end as a JSON

This method to create user 

@RequestMapping(value = "/createUser", method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> createUser(@RequestBody UserMain json) throws ParseException 
{
System.out.println("UserDetailsController.editUser()");
String response=userservices.createUser(json);
return new ResponseEntity<String>(response, HttpStatus.OK);
}

User services method :

This Method is used to create agent:

@PostMapping("/createUser")
public String createUser(@RequestBody UserMain user) {
System.out.println("UserDetailsController.createUser()");

try {
if (user.getId() == null) {
int count = getUserEmailIdCount(user.getEmailId());

if (count == 0) {
String userresult = createAgentOnKeyclock(user);
return userresult;

} else {
JSONObject obj = new JSONObject();
return "Failure";
}

} 
      }
catch(Exception e) {
return "Failure";
}
}

This method to get if the email id is existing and size of list :

public int getUserEmailIdCount(String emilId) {
System.out.println("UserServices.getUserEmailIdCount()");
List<UserMain> list= usermainRepo.findAllByEmailId(emilId);
return list.size();

}

This method is used to create user-id and password to the keycloack.\

public String createAgentOnKeyclock(UserMain usermain) {

try {
String serverUrl = Credentials.KEYCLOAK_SERVER_URL;
String realm = Credentials.KEYCLOAK_RELAM;
String clientId = Credentials.KEYCLOAK_CLIENT_ID;
String clientSecret = Credentials.KEYCLOAK_SECREAT_KEY;

Keycloak keycloak = KeycloakBuilder.builder() //
.serverUrl(serverUrl) //
.realm(Credentials.KEYCLOAK_RELAM) //
.grantType(OAuth2Constants.PASSWORD) //
.clientId(clientId) //
.clientSecret(clientSecret) //
.username(Credentials.KEYCLOAK_USER_NAME) //
.password(Credentials.KEYCLOAK_USER_PASSWORD) //
.build();

// Define user
UserRepresentation user = new UserRepresentation();
user.setEnabled(true);
user.setUsername(usermain.getEmailId());
user.setFirstName(usermain.getFirstName());
user.setLastName(usermain.getLastName());
user.setEmail(usermain.getEmailId());

// Get realm
RealmResource realmResource = keycloak.realm(realm);
UsersResource userRessource = realmResource.users();

Response response = userRessource.create(user);

System.out.println("response : " + response);

String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");

System.out.println("userId : " + userId);
// Define password credential
CredentialRepresentation passwordCred = new CredentialRepresentation();
//
passwordCred.setTemporary(true);
passwordCred.setType(CredentialRepresentation.PASSWORD);
passwordCred.setValue(Credentials.DEFAULT_PASSWORD_AGENT_CREATION);

// Set password credential
userRessource.get(userId).resetPassword(passwordCred);
String userObj = createUser(usermain,userId);
return userObj;
} catch (Exception e) {
e.printStackTrace();
return "Failure";
}
}

Credential page to store keycloak credentials:

Keycloak client details (details from installation JSON from keycloak)

  • public static final String KEYCLOAK_SERVER_URL = “Keycloak server url“;
  • public static final String KEYCLOAK_RELAM = “Realm name“;
  • public static final String KEYCLOAK_CLIENT_ID = “Client name“;
  • public static final String KEYCLOAK_SECREAT_KEY = “Secret key of new client“;

First user in new realm with manage user permission details 

  • public static final String KEYCLOAK_USER_NAME = “First user emailId“;
  • public static final String KEYCLOAK_USER_PASSWORD = “First user password“;

Default password is stored in keycloak

  • public static final String DEFAULT_PASSWORD_AGENT_CREATION = “Default password“;
  • public static final String DB_SCHEMA_NAME = null;

Conclusion:

Using keycloak in the application makes it more secure and easy for maintaining user data for login.

Join the discussion 2 Comments

Leave a Reply