From 977670c25cf11e519b2046bb1b5b8f3b530f0a75 Mon Sep 17 00:00:00 2001 From: Rolain Djeumen Date: Mon, 15 Apr 2024 15:32:24 +0100 Subject: [PATCH] feat(oxshibboleth): added support for logout redirect url Signed-off-by: Rolain Djeumen --- .../gluu/idp/context/GluuScratchContext.java | 1 + .../externalauth/ShibOxAuthAuthServlet.java | 5 +- .../model/GluuVanillaTrustRelationship.java | 87 +++++++++++++++++++ .../idp/service/GluuCustomViewService.java | 49 +++++++++++ .../GluuVanillaTrustRelationshipService.java | 66 ++++++++++++++ .../017.oxauth-authn-global-config-gvt.patch | 12 +++ .../018.add-gluu-custom-view-bean.patch | 32 +++++++ .../patches/019.add-custom-view-context.patch | 67 ++++++++++++++ 8 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 shib-oxauth-authn/src/main/java/org/gluu/idp/model/GluuVanillaTrustRelationship.java create mode 100644 shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuCustomViewService.java create mode 100644 shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuVanillaTrustRelationshipService.java create mode 100644 static/src/main/patches/017.oxauth-authn-global-config-gvt.patch create mode 100644 static/src/main/patches/018.add-gluu-custom-view-bean.patch create mode 100644 static/src/main/patches/019.add-custom-view-context.patch diff --git a/shib-oxauth-authn/src/main/java/org/gluu/idp/context/GluuScratchContext.java b/shib-oxauth-authn/src/main/java/org/gluu/idp/context/GluuScratchContext.java index e352427..c121d0f 100644 --- a/shib-oxauth-authn/src/main/java/org/gluu/idp/context/GluuScratchContext.java +++ b/shib-oxauth-authn/src/main/java/org/gluu/idp/context/GluuScratchContext.java @@ -70,4 +70,5 @@ public String getExtraHttpParameters() { return null; } } + } diff --git a/shib-oxauth-authn/src/main/java/org/gluu/idp/externalauth/ShibOxAuthAuthServlet.java b/shib-oxauth-authn/src/main/java/org/gluu/idp/externalauth/ShibOxAuthAuthServlet.java index 817e062..060ec2a 100644 --- a/shib-oxauth-authn/src/main/java/org/gluu/idp/externalauth/ShibOxAuthAuthServlet.java +++ b/shib-oxauth-authn/src/main/java/org/gluu/idp/externalauth/ShibOxAuthAuthServlet.java @@ -229,6 +229,7 @@ private void processAuthorizationResponse(final HttpServletRequest request, fina final UserProfile userProfile = authClient.getUserProfile(openIdCredentials, context); LOG.debug("User profile : {}", userProfile); + if (userProfile == null) { LOG.error("Token validation failed, returning InvalidToken"); @@ -320,7 +321,7 @@ protected void startLoginRequest(final HttpServletRequest request, final HttpSer } } }catch(ExternalAuthenticationException e) { - LOG.debug("Could not set extra parameters for the request. Extra request parameters will not be available to oxAuth",e); + LOG.info("Could not set extra parameters for the request. Extra request parameters will not be available to oxAuth",e); } @@ -338,7 +339,7 @@ protected void startLoginRequest(final HttpServletRequest request, final HttpSer Function authenticationContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class); final RelyingPartyContext relyingPartyContext = authenticationContextLookupStrategy.apply(profileRequestContext); if (relyingPartyContext != null) { - ProfileConfiguration profileConfiguration = relyingPartyContext.getProfileConfig(); + ProfileConfiguration profileConfiguration = relyingPartyContext.getProfileConfig(); if (profileConfiguration instanceof BrowserSSOProfileConfiguration) { List principals = ((BrowserSSOProfileConfiguration) profileConfiguration).getDefaultAuthenticationMethods(profileRequestContext); acrs = principals.stream() diff --git a/shib-oxauth-authn/src/main/java/org/gluu/idp/model/GluuVanillaTrustRelationship.java b/shib-oxauth-authn/src/main/java/org/gluu/idp/model/GluuVanillaTrustRelationship.java new file mode 100644 index 0000000..f54cc4b --- /dev/null +++ b/shib-oxauth-authn/src/main/java/org/gluu/idp/model/GluuVanillaTrustRelationship.java @@ -0,0 +1,87 @@ +package org.gluu.idp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSeeAlso; + +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.DN; +import org.gluu.persist.annotation.ObjectClass; +import org.gluu.persist.model.base.InumEntry; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Vanilla Trust relationship model + * Just enough data in it to extract some useful information + * (e.g. logout redirect uri) + */ + +@DataEntry() +@ObjectClass(value="gluuSAMLconfig") +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown=true) +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class GluuVanillaTrustRelationship { + + private static final long serialVersionUID = -1L; + + @DN + private String dn; + + @AttributeName(ignoreDuringUpdate=true) + private String inum; + + @AttributeName(name = "oxAuthPostLogoutRedirectURI") + private String spLogoutURL; + + @AttributeName(name="spLogoutRedirectUrl") + private String spLogoutRedirectUrl; + + public String getDn() { + + return this.dn; + } + + public void setDn(final String dn) { + + this.dn = dn; + } + + public String getInum() { + + return this.inum; + } + + public void setInum(final String inum) { + + this.inum = inum; + } + + public String getSpLogoutURL() { + + return this.spLogoutURL; + } + + public void setSpLogoutURL(final String spLogoutURL) { + + this.spLogoutURL = spLogoutURL; + } + + public String getSpLogoutRedirectUrl() { + + return this.spLogoutRedirectUrl; + } + + public void setSpLogoutRedirectUrl(final String spLogoutRedirectUrl) { + + this.spLogoutRedirectUrl = spLogoutRedirectUrl; + } + +} diff --git a/shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuCustomViewService.java b/shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuCustomViewService.java new file mode 100644 index 0000000..eca93b0 --- /dev/null +++ b/shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuCustomViewService.java @@ -0,0 +1,49 @@ +package org.gluu.idp.service; + +import java.util.function.Function; + +import net.shibboleth.idp.profile.context.RelyingPartyContext; +import org.gluu.idp.model.GluuVanillaTrustRelationship; +import org.gluu.idp.service.GluuVanillaTrustRelationshipService; + +import org.opensaml.messaging.context.navigate.ChildContextLookup; +import org.opensaml.profile.context.ProfileRequestContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + + +public class GluuCustomViewService { + + private final Logger log = LoggerFactory.getLogger(GluuCustomViewService.class); + private GluuVanillaTrustRelationshipService trService; + + public GluuCustomViewService(final GluuVanillaTrustRelationshipService trService) { + + log.info("GluuCustomViewService() constructor"); + this.trService = trService; + } + + public String getRelyingPartyLogoutRedirectUrl(final ProfileRequestContext prContext) { + + try { + log.debug("Getting logout url for the currently active relying party"); + final Function rpCtxLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class); + final RelyingPartyContext rpCtx = rpCtxLookupStrategy.apply(prContext); + if(rpCtx == null) { + log.debug("Could not obtain the relying party context from the profile request context"); + return null; + } + GluuVanillaTrustRelationship tr = trService.findTrustRelationshipByRelyingParty(rpCtx.getRelyingPartyId()); + if(tr == null) { + log.debug("No trust relationship found associated to the relying party {}",rpCtx.getRelyingPartyId()); + return null; + } + return tr.getSpLogoutRedirectUrl(); + }catch(Exception e) { + log.debug("Error while fetching logout url for currently active relying party",e); + return null; + } + } +} diff --git a/shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuVanillaTrustRelationshipService.java b/shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuVanillaTrustRelationshipService.java new file mode 100644 index 0000000..a40d72a --- /dev/null +++ b/shib-oxauth-authn/src/main/java/org/gluu/idp/service/GluuVanillaTrustRelationshipService.java @@ -0,0 +1,66 @@ +package org.gluu.idp.service; + +import java.util.List; + +import org.gluu.idp.externalauth.openid.conf.IdpConfigurationFactory; +import org.gluu.search.filter.Filter; + +import org.gluu.idp.model.GluuVanillaTrustRelationship; +import org.gluu.persist.PersistenceEntryManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class GluuVanillaTrustRelationshipService { + + private static final String ORG_DN = "o=gluu"; + private static final Logger log = LoggerFactory.getLogger(GluuVanillaTrustRelationshipService.class); + + private PersistenceEntryManager persistenceEntryManager; + + public GluuVanillaTrustRelationshipService(final IdpConfigurationFactory configurationFactory) { + + persistenceEntryManager = configurationFactory.getPersistenceEntryManager(); + } + + public GluuVanillaTrustRelationship findTrustRelationshipByInum(String inum) { + + try { + log.debug("findTrustRelationshipByInum() -- inum {}",inum); + String [] attributes= new String[] {"dn","inum","oxAuthPostLogoutRedirectURI","spLogoutRedirectUrl"}; + return persistenceEntryManager.find(getDnForTrustRelationship(inum),GluuVanillaTrustRelationship.class,attributes); + }catch(Exception e) { + log.error(String.format("Error fetching TrustRelationship with inum -- %s",inum),e); + return null; + } + } + + public GluuVanillaTrustRelationship findTrustRelationshipByRelyingParty(String relyingPartyId) { + + try { + log.debug("findTrustRelationshipByRelyingParty() -- relyingPartyId {}",relyingPartyId); + final String [] attributes = new String [] {"dn","inum","oxAuthPostLogoutRedirectURI","spLogoutRedirectUrl"}; + String dn = getDnForTrustRelationship(null); + Filter filter = Filter.createEqualityFilter("gluuEntityId",relyingPartyId).multiValued(); + List trlist = persistenceEntryManager.findEntries(dn,GluuVanillaTrustRelationship.class,filter,attributes,1); + if(trlist.isEmpty()) { + log.debug("findTrustRelationshipByRelyingParty() -- no entries found for relyingParty {}",relyingPartyId); + return null; + } + return trlist.get(0); + }catch(Exception e) { + log.error(String.format("Error fetching TrustRelationship with relyingPartyId -- %s",relyingPartyId),e); + return null; + } + } + + public String getDnForTrustRelationship(final String inum) { + + if(inum == null || inum.isEmpty()) { + + return String.format("ou=trustRelationships,%s",ORG_DN); + }else { + return String.format("inum=%s,ou=trustRelationships,%s",inum,ORG_DN); + } + } +} diff --git a/static/src/main/patches/017.oxauth-authn-global-config-gvt.patch b/static/src/main/patches/017.oxauth-authn-global-config-gvt.patch new file mode 100644 index 0000000..49cb3ac --- /dev/null +++ b/static/src/main/patches/017.oxauth-authn-global-config-gvt.patch @@ -0,0 +1,12 @@ +diff -aurN shibboleth-idp.orig/conf/authn/oxauth-authn-global.xml shibboleth-idp/conf/authn/oxauth-authn-global.xml +--- shibboleth-idp.orig/conf/authn/oxauth-authn-global.xml 2024-04-08 14:17:50.468803551 +0100 ++++ shibboleth-idp/conf/authn/oxauth-authn-global.xml 2024-04-08 15:39:24.208219767 +0100 +@@ -55,4 +55,8 @@ + + + ++ ++ ++ ++ + diff --git a/static/src/main/patches/018.add-gluu-custom-view-bean.patch b/static/src/main/patches/018.add-gluu-custom-view-bean.patch new file mode 100644 index 0000000..a5aed3c --- /dev/null +++ b/static/src/main/patches/018.add-gluu-custom-view-bean.patch @@ -0,0 +1,32 @@ +diff -aurN shibboleth-idp.orig/conf/global.xml shibboleth-idp/conf/global.xml +--- shibboleth-idp.orig/conf/global.xml 2024-04-08 15:47:28.754193000 +0100 ++++ shibboleth-idp/conf/global.xml 2024-04-10 10:28:12.856588766 +0100 +@@ -64,5 +64,6 @@ + + + ++ + + +diff -aurN shibboleth-idp.orig/conf/gluu-custom-view-bean.xml shibboleth-idp/conf/gluu-custom-view-bean.xml +--- shibboleth-idp.orig/conf/gluu-custom-view-bean.xml 1970-01-01 01:00:00.000000000 +0100 ++++ shibboleth-idp/conf/gluu-custom-view-bean.xml 2024-04-10 11:16:32.107680798 +0100 +@@ -0,0 +1,18 @@ ++ ++ ++ ++ ++ ++ ++ diff --git a/static/src/main/patches/019.add-custom-view-context.patch b/static/src/main/patches/019.add-custom-view-context.patch new file mode 100644 index 0000000..2e28ac4 --- /dev/null +++ b/static/src/main/patches/019.add-custom-view-context.patch @@ -0,0 +1,67 @@ +diff -aurN shibboleth-idp.orig/views/logout-complete.vm shibboleth-idp/views/logout-complete.vm +--- shibboleth-idp.orig/views/logout-complete.vm 2024-04-14 12:46:38.725262468 +0100 ++++ shibboleth-idp/views/logout-complete.vm 2024-04-12 17:50:00.374229000 +0100 +@@ -16,6 +16,8 @@ + ## + #set ($activeIdPSessions = $logoutContext and !$logoutContext.getIdPSessions().isEmpty()) + #set ($activeSPSessions = $logoutContext and !$logoutContext.getSessionMap().isEmpty()) ++#set ($gluuLogoutRedirectUrl = $custom.getRelyingPartyLogoutRedirectUrl($profileRequestContext)) ++#set ($gluuLogoutRedirectMethod="get") + + + +diff -aurN shibboleth-idp.orig/views/logout.vm shibboleth-idp/views/logout.vm +--- shibboleth-idp.orig/views/logout.vm 2024-04-14 12:46:38.729262496 +0100 ++++ shibboleth-idp/views/logout.vm 2024-04-12 18:00:19.684950000 +0100 +@@ -20,6 +20,8 @@ + #end + #set ($promptForIdP = $logoutContext and !$logoutContext.getIdPSessions().isEmpty()) + #set ($promptForSP = $logoutContext and !$logoutContext.getSessionMap().isEmpty()) ++#set ($gluuLogoutRedirectUrl = $custom.getRelyingPartyLogoutRedirectUrl($profileRequestContext)) ++#set ($gluuLogoutRedirectMethod="get") + + + +@@ -100,6 +102,22 @@ +

#springMessageText("idp.logout.complete", "The logout operation is complete, and no other services appear to have been accessed during this session.")

+ + ++ ++ ++ #if($gluuLogoutRedirectUrl) ++

++ ++ #springMessageText("idp.gluulogout.redirect-msg","You will be redirected shortly") ++ ++

++
++

++ ++

++
++ #end + #end + + + +- ++ #if($gluuLogoutRedirectUrl) ++ ++ #end + +