Pac4j with Shiro and Keycloak - how can I manage my Permissions (Authorization)

243 Views Asked by At

I´m currently try to setup Shiro with Keycloak. I searched on the internet and found some shiro.ini settings for setup a OIDC Config with Keycloak. I´ve setup Shiro before without Keycloak authentication - everything was based on JDBC realm. I´m managing my permissions with Shiro. I have in my app some SQL tables (permission_role_object). Therefore I have those JDBC queries:

jdbcRealm.userRolesQuery = ...
jdbcRealm.permissionsQuery = ...

My question is, how can I have a relationship to my pac4jRealm (= Keycloak authentication) to my SQL table for the permissions? I guess I need also to add something in the shiro.ini:

pac4jRealm.userRolesQuery = ...
pac4jRealm.permissionsQuery = ...

This is my current shiro.ini

[main]
#### Session
sessionIdCookie=org.apache.shiro.web.servlet.SimpleCookie
#sessionIdCookie.path = /
sessionIdCookie.httpOnly = true
sessionIdCookie.name = sid
sessionIdCookie.domain = localhost
sessionIdCookie.maxAge=28800000
sessionIdCookie.secure = true
sessionIdCookie.sameSite = LAX

sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionIdCookie=$sessionIdCookie
sessionManager.sessionIdCookieEnabled=true
securityManager.sessionManager=$sessionManager
# Session Timeout nach 8 Stunden
sessionManager.globalSessionTimeout= 28800000

sessionListener1= de.dpunkt.myaktion.util.MySessionListener1
sessionManager.sessionListeners=$sessionListener1

# Session validation = 5 minutes
sessionManager.sessionValidationInterval = 300000


#sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
#securityManager.sessionMode=native


sessionValidationScheduler=org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
sessionValidationScheduler.interval = 60000
sessionValidationScheduler.sessionManager=$sessionManager
sessionManager.sessionValidationScheduler=$sessionValidationScheduler
sessionManager.deleteInvalidSessions=true
#sessionFactory=org.apache.shiro.session.mgt.OnlineSessionFactory
#sessionManager.sessionFactory=$sessionFactory
#securityManager.subjectDAO.sessionStorageEvaluator.sessionStorageEnabled = false

#Keycloack
oidcConfig = org.pac4j.oidc.config.OidcConfiguration
oidcConfig.withState = false
oidcConfig.discoveryURI = http://localhost:9009/auth/realms/myapp/.well-known/openid-configuration
oidcConfig.clientId = myapp
oidcConfig.secret = 112345679465456
oidcConfig.clientAuthenticationMethodAsString = client_secret_basic
oidcClient = org.pac4j.oidc.client.OidcClient
oidcClient.configuration = $oidcConfig

clients = org.pac4j.core.client.Clients
clients.callbackUrl = http://localhost:8080/api/callback
clients.clients = $oidcClient

pac4jRealm = io.buji.pac4j.realm.Pac4jRealm
pac4jRealm.principalNameAttribute = preferred_username
pac4jSubjectFactory = io.buji.pac4j.subject.Pac4jSubjectFactory

pac4jRealm.principalNameAttribute = preferred_username
securityManager.subjectFactory = $pac4jSubjectFactory

#usernameAuthorizer = myapp.util.UsernameAuthorizer
#usernameAuthorizer.elements = ${user1},${user2}

config = org.pac4j.core.config.Config
config.clients = $clients
#config.authorizers = username:$usernameAuthorizer

oidcSecurityFilter = io.buji.pac4j.filter.SecurityFilter
oidcSecurityFilter.config = $config
oidcSecurityFilter.clients = oidcClient
oidcSecurityFilter.authorizers = +username

# DataSource
ds = com.mysql.cj.jdbc.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = test1234
ds.databaseName = myapp
ds.useSSL = false
ds.serverTimezone = Europe/Berlin

# password hashing specification, put something big for hasIterations
sha512Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha512Matcher.hashAlgorithmName=SHA-512
sha512Matcher.hashIterations=1

# Configure JDBC realm datasource.
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = select password FROM user where UPPER(email)=UPPER(?) and status = 'ACTIVE'
jdbcRealm.userRolesQuery = SELECT r.unique_name FROM permission_role_employee pe JOIN permission_role r ON pe.permission_role_fk  = r.permission_role_id JOIN employee e ON pe.employee_fk = e.employee_id JOIN user u ON e.user_fk = u.user_id WHERE UPPER(u.email)=UPPER(?) AND pe.delete_flag = false
jdbcRealm.permissionsQuery = SELECT p.unique_name FROM permission_role_object po JOIN permission p ON po.permission_fk  = p.permission_id JOIN permission_role r ON po.permission_role_fk = r.permission_role_id WHERE UPPER(r.unique_name)=UPPER(?) AND po.delete_flag = false
jdbcRealm.dataSource = $ds
jdbcRealm.credentialsMatcher = $sha512Matcher

# Realm for Token Login
tcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
tcRealm.permissionsLookupEnabled = true
tcRealm.authenticationQuery = SELECT token FROM api_token WHERE token = ?
tcRealm.userRolesQuery = SELECT r.unique_name FROM permission_role_employee pe JOIN permission_role r ON pe.permission_role_fk  = r.permission_role_id JOIN employee e ON pe.employee_fk = e.employee_id JOIN api_token t ON t.employee_fk = e.employee_id WHERE UPPER(t.token)=UPPER(?) AND t.delete_flag = false
tcRealm.permissionsQuery = SELECT p.unique_name FROM permission_role_object po JOIN permission p ON po.permission_fk  = p.permission_id JOIN permission_role r ON po.permission_role_fk = r.permission_role_id WHERE UPPER(r.unique_name)=UPPER(?) AND po.delete_flag = false
tcRealm.dataSource = $ds

# AuthStrategy
authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator
authcStrategy = org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy

authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator = $authenticator
securityManager.authenticator.authenticationStrategy = $authcStrategy
securityManager.realms = $jdbcRealm, $tcRealm, $pac4jRealm

# Caching
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager

# Using default form based security filter org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authc.loginUrl = /common/login.jsf
authc.successUrl = /portal/dashboard.jsf


# Redirect to an access denied page if user does not have access rights
#[roles]
#roles.unauthorizedUrl = /common/access-denied.jsf
#perms.unauthorizedUrl = /accessdenied.jsp

anyofpermission = com.myapp.util.CustomPermissionsAuthorizationFilter

# Protected URLs
[urls]
/service = noSessionCreation, anon
    
## OTHER
/WEB-INF/layout/portal/** = authc
/portal/** = authc
/admin/** = authc
/community/** = authc
1

There are 1 best solutions below

9
jleleu On

The Shiro JdbcRealm is an AuthorizingRealm with JDBC capabilities.

The pac4jRealm is also an AuthorizingRealm with pac4j logic, there is no JDBC capability in the pac4jRealm.

Thus you cannot configure things only in the shiro.ini file.

You should certainly create a pac4j AuthorizationGenerator which retrieves the roles and permissions from the database and set it to the OidcClient.