Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

Summary

  • Customer has a central user management system such as keyCloak

  • Customer wants to use KeyCloak to login into Iguana

  • Leverage KeyCloak API and Iguana External Authentication with From HTTPS Channel for login

Design

Considerations

  • Recommended to use a dedicated Iguana with a From HTTP Channel for Authentication, separate from the Production Iguana (Note: API call temporarily logs Username and Password).

  • When external authentication is used, Iguana creates an “Ad Hoc” user session. Iguana will create an Ad Hoc user with no permissions if there are no matching Roles setup in both Iguana and KeyCloak. If a matching Iguana Role exists, Iguana will login the Ad Hoc user with the matching Iguana Roles. 

  • The KeyCloak password and Iguana password do not need to match. Only the Role names.

How to

KeyCloak Sandbox Configuration

In KeyCloak ensure the following configurations are set up:

  1. Create a Client to represent the Iguana application. Assign a client_Id and turn on client authentication, with Standard Flow and Direct Access Grants checked.

  2. Create Users (username and passwords for each person accessing Iguana)

  3. Create and Assign Roles (these Role names must match the Roles created within Iguana.)

Iguana Configuration

Configure a From HTTP > To Channel interface to authenticate with KeyCloak via RESTful API. Enable Iguana to use the External Authentication URL of your From HTTP channel in Settings > Authentication.

When enabled, all Iguana login requests will query this URL to validate user credentials (and fallback to local Iguana validation if the query fails). Requests are formatted as HTTP GET, and credentials are passed in clear plaintext.

GET /keycloak?name=admin&password=password

When the From HTTP authentication channel receives the GET request, the username and password can be used to authenticate with KeyCloak and validate the User and Role permissions. To validate with KeyCloak, send a POST request to the authentication token endpoint.

http://localhost:8080/realms/{{realm}}/protocol/openid-connect/token

If the User exists in KeyCloak, the API will respond with a JWT (JSON Web Token). The payload of the JWT includes the encoded User’s assigned Roles in KeyCloak.

If the user exists in KeyCloak and the request is successful, have Iguana respond and log a 1 with a list of all assigned Roles.

Code Example

function main(Data)

   -- Parse login GET Request for username and password
   local request = net.http.parseRequest{data=Data}
   local name = request.get_params.name
   local pass = request.get_params.password

   local success = false

   -- validate username and password in KeyCloak
   -- if success, log 1 and list of assigned roles.
   success, roles = validateViaKeycloak(name, pass)

   if success then
      body = '1'
      for _, role in pairs(roles) do
         body = body .. '\r\n' .. role
      end
   else
      body = '0'
   end

   local Response = net.http.respond{
      body = body,
      entity_type = "text/plain"
   }

   iguana.logInfo('Returning "' .. body .. '" for: ' .. name)

end


-- Authenticate user with KeyCloak
function validateViaKeycloak(name, pass)
   local clientId = 'iguana'
   local tokenURL = 'http://localhost:8080/realms/master/protocol/openid-connect/token'

   local tokenRequest = net.http.post{
      url = tokenURL,
      headers = {['Content-Type']='application/x-www-form-urlencoded'},
      parameters = {
         ['grant_type'] = 'password',
         ['client_id']  = clientId,
         ['username']   = name,
         ['password']   = pass
      },
      live=true
   }

   local response = json.parse{data=tokenRequest}
   local token = response.access_token

   -- If query succeeds, returns a valid token with user details, nil otherwise.
   if token == nil then
      return false
   else
      return true, getRoles(name, token)
   end
end


function getRoles(name, token)
   -- split and decode jwt payload containing user roles
   local roles = {}
   local jwt = token:split('.')
   local payload = filter.base64.dec(jwt[2])
   local payloadDetails = json.parse(payload)
   local roles = payloadDetails.realm_access.roles

   return roles 
end

Reference

  • No labels