From dadbce085023029ce43bd356325f408cea7adb5a Mon Sep 17 00:00:00 2001 From: Fabio Santaniello Date: Wed, 12 Jun 2024 11:45:34 +0200 Subject: [PATCH] Revert "db changes only" This reverts commit b5d38e6f4ba67d0652c5605a322d05ceaec54a66. --- pom.xml | 26 ++++++ wegas-app/src/main/webapp/WEB-INF/shiro.ini | 30 ++++++- wegas-core/pom.xml | 27 ++++++ .../security/oidc/Pac4jOidcWegasRealm.java | 90 +++++++++++++++++++ .../core/security/oidc/WegasOidcClient.java | 14 +++ .../security/oidc/WegasOidcConfiguration.java | 20 +++++ .../oidc/WegasRememberMeAuthGenerator.java | 19 ++++ 7 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 wegas-core/src/main/java/com/wegas/core/security/oidc/Pac4jOidcWegasRealm.java create mode 100644 wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcClient.java create mode 100644 wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcConfiguration.java create mode 100644 wegas-core/src/main/java/com/wegas/core/security/oidc/WegasRememberMeAuthGenerator.java diff --git a/pom.xml b/pom.xml index 47c944d432..1d41d86cf3 100755 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,10 @@ 10.0.0 1.12.0 + 6.0.2 + 9.0.1 + 8.0.1 + 6.2023.9 4.13.1 @@ -182,6 +186,28 @@ + + io.buji + buji-pac4j + ${bujiVersion} + + + org.pac4j + jakartaee-pac4j + ${jakartaPac4jVersion} + + + + org.pac4j + pac4j-jakartaee + ${pac4jVersion} + + + org.pac4j + pac4j-oidc + ${pac4jVersion} + + fish.payara.api diff --git a/wegas-app/src/main/webapp/WEB-INF/shiro.ini b/wegas-app/src/main/webapp/WEB-INF/shiro.ini index 5f1b7a9876..a9060d5437 100644 --- a/wegas-app/src/main/webapp/WEB-INF/shiro.ini +++ b/wegas-app/src/main/webapp/WEB-INF/shiro.ini @@ -60,8 +60,12 @@ aaiCredentialsMatcher = com.wegas.core.security.aai.AaiCredentialsMatcher aaiRealm = com.wegas.core.security.aai.AaiRealm aaiRealm.credentialsMatcher = $aaiCredentialsMatcher +#pac4j Realm +pac4jRealm = com.wegas.core.security.oidc.Pac4jOidcWegasRealm +pac4jRealm.credentialsMatcher = $aaiCredentialsMatcher + # Assign realms to security manager -securityManager.realms = $jpaRealm, $guestRealm, $aaiRealm, $jpaTokenRealm +securityManager.realms = $jpaRealm, $guestRealm, $pac4jRealm, $aaiRealm, $jpaTokenRealm srm = com.wegas.core.security.util.ShiroRememberManager securityManager.rememberMeManager = $srm @@ -76,9 +80,28 @@ authc.successUrl = / # Redirect to error page if user does not have access rights roles.unauthorizedUrl = /wegas-app/jsf/error/accessdenied.html -# Redirect logout to logoutpage +# Redirect logout to logout page logout.redirectUrl = / +oidcConfig = com.wegas.core.security.oidc.WegasOidcConfiguration +oidcClient = com.wegas.core.security.oidc.WegasOidcClient +oidcClient.configuration = $oidcConfig + +wegasRememberMeAuthGenerator = com.wegas.core.security.oidc.WegasRememberMeAuthGenerator +oidcClient.authorizationGenerator = $wegasRememberMeAuthGenerator + + +clients.clients = $oidcClient + +oidcSecurityFilter = org.pac4j.jee.filter.SecurityFilter +# $config is defined in pac4j +oidcSecurityFilter.config = $config +oidcSecurityFilter.clients = WegasOidcClient + +callbackFilter = org.pac4j.jee.filter.CallbackFilter +callbackFilter.config = $config +callbackFilter.renewSession = false + [urls] #logout #/logout=logout @@ -89,6 +112,9 @@ logout.redirectUrl = / /host.html=authc /game-play.html=authc +/rest/Oidc/Login=oidcSecurityFilter + +/rest/Oidc/Callback=callbackFilter # force ssl for login page #/login.html=ssl[8443], authc diff --git a/wegas-core/pom.xml b/wegas-core/pom.xml index 8cb28afdc0..5d420f57b7 100644 --- a/wegas-core/pom.xml +++ b/wegas-core/pom.xml @@ -43,6 +43,33 @@ + + io.buji + buji-pac4j + + + org.pac4j + pac4j-javaee + + + org.apache.shiro + shiro-web + + + + + org.pac4j + jakartaee-pac4j + + + + org.pac4j + pac4j-jakartaee + + + org.pac4j + pac4j-oidc + ch.albasim.wegas wegas-annotations diff --git a/wegas-core/src/main/java/com/wegas/core/security/oidc/Pac4jOidcWegasRealm.java b/wegas-core/src/main/java/com/wegas/core/security/oidc/Pac4jOidcWegasRealm.java new file mode 100644 index 0000000000..18f6a4f837 --- /dev/null +++ b/wegas-core/src/main/java/com/wegas/core/security/oidc/Pac4jOidcWegasRealm.java @@ -0,0 +1,90 @@ +package com.wegas.core.security.oidc; + +import com.wegas.core.Helper; +import com.wegas.core.ejb.RequestFacade; +import com.wegas.core.ejb.RequestManager; +import com.wegas.core.exception.internal.WegasNoResultException; +import com.wegas.core.security.aai.AaiAccount; +import com.wegas.core.security.aai.AaiAuthenticationInfo; +import com.wegas.core.security.aai.AaiUserDetails; +import com.wegas.core.security.ejb.AccountFacade; +import com.wegas.core.security.ejb.UserFacade; +import com.wegas.core.security.persistence.User; +import io.buji.pac4j.realm.Pac4jRealm; +import io.buji.pac4j.token.Pac4jToken; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.subject.PrincipalCollection; +import org.pac4j.core.profile.UserProfile; +import org.pac4j.oidc.profile.OidcProfile; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class Pac4jOidcWegasRealm extends Pac4jRealm { + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Pac4jOidcWegasRealm.class); + + public Pac4jOidcWegasRealm() { + setAuthenticationTokenClass(Pac4jToken.class); + setName("Pac4jOidcWegasRealm"); //This name must match the name in the User class's getPrincipals() method + } + + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + //Effective authorisations are fetched by JpaRealm in all case + return new SimpleAuthorizationInfo(); + } + + @Override + protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken authenticationToken) { + + //TODO check already loggedin? + + if (!Boolean.parseBoolean(Helper.getWegasProperty("oidc.enabled"))) { + logger.warn("EduID OIDC is disabled"); + return null; + } + + final Pac4jToken token = (Pac4jToken) authenticationToken; + final List profiles = token.getProfiles(); + + AaiUserDetails userDetails = new AaiUserDetails(); + OidcProfile profile = (OidcProfile) profiles.get(0); + + // reject if values are null! + if(profile.getId().isEmpty() || profile.getFirstName().isEmpty() || profile.getFamilyName().isEmpty() || profile.getEmail().isEmpty()) + throw new AuthenticationException("Profile does not provide information"); + + userDetails.setPersistentId(null); //OLD AAI + userDetails.setEduIdPairwiseId(profile.getId()); + userDetails.setEmail(profile.getEmail()); + userDetails.setFirstname(profile.getFirstName()); + userDetails.setLastname(profile.getFamilyName()); + userDetails.setRememberMe(false); + userDetails.setHomeOrg("EduId"); //affiliations are not (easily) accessible with edu id, so we just set eduid + + AccountFacade accountFacade = AccountFacade.lookup(); + RequestManager requestManager = RequestFacade.lookup().getRequestManager(); + try { + requestManager.su(); + AaiAccount account = accountFacade.findByEduIdPairwiseId(userDetails.getEduIdPairwiseId()); + accountFacade.refreshEduIDAccount(userDetails); + logger.info("EduID user found, logging in user " + account.getId()); + return new AaiAuthenticationInfo(account.getId(), userDetails, getName()); + } catch (WegasNoResultException ex) { + logger.info("User not found, creating new account."); + AaiAccount account = AaiAccount.buildForEduIdPairwiseId(userDetails); + User user = new User(account); + UserFacade userFacade = UserFacade.lookup(); + userFacade.create(user); + return new AaiAuthenticationInfo(account.getId(), userDetails, getName()); + } catch (Exception e) { + return null; + } finally { + requestManager.releaseSu(); + } + } +} \ No newline at end of file diff --git a/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcClient.java b/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcClient.java new file mode 100644 index 0000000000..6d2a7c49d9 --- /dev/null +++ b/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcClient.java @@ -0,0 +1,14 @@ +package com.wegas.core.security.oidc; + +import com.wegas.core.Helper; +import org.pac4j.core.http.callback.NoParameterCallbackUrlResolver; +import org.pac4j.oidc.client.OidcClient; + +public class WegasOidcClient extends OidcClient { + + public WegasOidcClient() { + super(); + this.setCallbackUrlResolver(new NoParameterCallbackUrlResolver()); + this.setCallbackUrl(Helper.getWegasProperty("oidc.callbackUrl","https://localhost:8443/rest/Oidc/Callback")); + } +} diff --git a/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcConfiguration.java b/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcConfiguration.java new file mode 100644 index 0000000000..b961e9dcfe --- /dev/null +++ b/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasOidcConfiguration.java @@ -0,0 +1,20 @@ +package com.wegas.core.security.oidc; + +import com.nimbusds.jose.JWSAlgorithm; +import com.wegas.core.Helper; +import org.pac4j.oidc.config.OidcConfiguration; + + +public class WegasOidcConfiguration extends OidcConfiguration { + public WegasOidcConfiguration() { + super(); + this.setDiscoveryURI(Helper.getWegasProperty("oidc.discoveryURI", "https://localhost:8443/.well-known/openid-configuration")); + this.setClientId(Helper.getWegasProperty("oidc.clientId", "1234")); + //TODO: use private key https://www.pac4j.org/docs/clients/openid-connect.html#3-advanced-configuration + this.setSecret(Helper.getWegasProperty("oidc.secret", "1234")); + this.setUseNonce(true); + this.setWithState(true); + this.setPreferredJwsAlgorithm(JWSAlgorithm.RS256); + this.addCustomParam("prompt", "consent"); + } +} diff --git a/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasRememberMeAuthGenerator.java b/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasRememberMeAuthGenerator.java new file mode 100644 index 0000000000..39894d9be4 --- /dev/null +++ b/wegas-core/src/main/java/com/wegas/core/security/oidc/WegasRememberMeAuthGenerator.java @@ -0,0 +1,19 @@ +package com.wegas.core.security.oidc; + +import com.wegas.core.Helper; +import org.pac4j.core.authorization.generator.AuthorizationGenerator; +import org.pac4j.core.context.CallContext; +import org.pac4j.core.profile.CommonProfile; +import org.pac4j.core.profile.UserProfile; + +import java.util.Optional; + + +public class WegasRememberMeAuthGenerator implements AuthorizationGenerator { + @Override + public Optional generate(final CallContext ctx, final UserProfile profile) { + ((CommonProfile) profile).removeLoginData(); // remove tokens + profile.setRemembered(Boolean.parseBoolean(Helper.getWegasProperty("oidc.useRememberMe", "false"))); + return Optional.of(profile); + } +}