DEV Community

Mohammed O. Tillawy
Mohammed O. Tillawy

Posted on

Rails and Keycloak, Authentication, Authorization, part three

In part one, we have discussed what Keycloak is.
In part two, we have setup our Rails application to use Keycloak for authentication.
In the third part, we will use Keycloak as a an extra security later to provide authorization checks for our API requests.

How does it work

This gem is a simple middle-ware that intercepts and filters the API requests before they are processed by the application.

Let us start with adding the gem rails_keycloak_authorization to our Gemfile.

# Gemfile
gem "rails_keycloak_authorization"
Enter fullscreen mode Exit fullscreen mode

Gem initializer config/initializers/rails_keycloak_authorization.rb

# initializers/rails_keycloak_authorization.rb 

# initializers/rails_keycloak_authorization.rb 

# the realm that contains the open-client client
RailsKeycloakAuthorization.keycloak_auth_client_realm_name = ENV.fetch("KEYCLOAK_AUTH_CLIENT_REALM_NAME", "dummy")

# the subject open-id client containing
RailsKeycloakAuthorization.keycloak_auth_client_id         = ENV.fetch("KEYCLOAK_AUTH_CLIENT_ID", "dummy-client")

# keycloak server_url
RailsKeycloakAuthorization.keycloak_server_url             = ENV.fetch("KEYCLOAK_SERVER_URL", "http://localhost:8080")

# keycloak server_domain
RailsKeycloakAuthorization.keycloak_server_domain          = ENV.fetch("KEYCLOAK_ADMIN_SERVER_DOMAIN", "localhost")

# keycloak realm that contains the admin-client
RailsKeycloakAuthorization.keycloak_admin_realm_name       = ENV.fetch("KEYCLOAK_ADMIN_REALM_NAME", "master")

# keycloak admin_client 
RailsKeycloakAuthorization.keycloak_admin_client_id        = ENV.fetch("KEYCLOAK_ADMIN_CLIENT_ID", "keycloak-admin")

# keycloak admin_client's secret
RailsKeycloakAuthorization.keycloak_admin_client_secret    = ENV.fetch("KEYCLOAK_ADMIN_CLIENT_SECRET", "keycloak-admin-client-secret-xxx")

# List of regext for pattern to protect
RailsKeycloakAuthorization.match_patterns                  = [
  /^\/organizations\.json/,
  /^\/api\/projects/,
  /^\/secrets\.json/,
  /^\/api\/secrets/
]
Enter fullscreen mode Exit fullscreen mode

Now we will add the UI tool, this part is not mandatory, but it will ease the setup.

mount RailsKeycloakAuthorization::Engine, at: "/rka", constraints: lambda { |request| request.remote_ip == "127.0.0.1" }
# Please make sure to secure this route, for the purposes of this tutorial, I will secure it by forcing the remote_ip to be localhost.
Enter fullscreen mode Exit fullscreen mode

Please make sure to restart the server.
Now open the Rails Keycloak Authorization Helper.

Image description

This tool consists of four tabs:

1 - Rails routes
In this tab we:

  • Map Rails controller into Keycloak Authorization Resources
  • Map Rails controller actions to scopes.
  • Attach Keycloak scopes to Keycloak resources

2 - Keycloak Policies
In this tab we:

  • Create policies.

3 - Keycloak Permissions
In this tab web:

  • Attach Policies to Resources.

4 - Keycloak Resource
You can skip this tab for now, it is work in progress.

So let us do the following:

Setup Routes: SecretsController#index only for managers.

We will:
1 - Create Keycloak resource: secrets_controller
2 - Create Keycloak scope: index
3 - Attach (scope: index) to (resource: secrets_controller)
3 - Create Policy: RKA-Policy-Managment for role: management-client-role
4 - Create Permission: (Policy: RKA-Policy-Managment) + (Resource: secrets_controller) + (Scope: index)
5 - Validate our setup

Let us do it:

  • Select tab: Rails Routes

    • The first route /secret(.:format), click inspect
    • click: Create Resource?
    • click: Create Scope?
    • click: Attach scope index to resource?
    • click: Close
  • Select tab: Keycloak Policies

    • In the Name type: RKA-Policy-Management
    • From the Role drop-down list select: management-client-role
    • Click Create
  • Select tab: Keycloak Permissions

    • From the drop-down list Policy select: RKA-Policy-Management
    • From the drop-down list Resource select: secrets_controller
    • From the drop-down Scope Select: index
    • Click Create

Now it is time to test it:


readonly username="manager@test.com";
readonly password="secret";
function get_access_token {
curl --silent \
    -d 'client_id=dummy-client' \
    -d 'client_secret=dummy-client-super-secret-xxx' \
    -d "username=${username}" \
    -d "password=${password}" \
    -d 'grant_type=password' \
    -d 'response_type=code' \
    -d 'scope=openid' \
    'http://localhost:8080/realms/dummy/protocol/openid-connect/token' | jq -r '.access_token'
}
access_token=$(get_access_token);
readonly url1="http://localhost:3000/secrets.json"
echo requesting ${url1};
curl -H "Authorization: bearer ${access_token}" ${url1};
Enter fullscreen mode Exit fullscreen mode

If you see the input: []%, setup is good.

You can find the source for this project in this Github repo

You can find the docker-compose & tofu setup in this Github repo

You can watch this video for quick walk through:

Top comments (0)