Skip to content

Commit

Permalink
feat(oxshibboleth): added support for logout redirect url
Browse files Browse the repository at this point in the history
Signed-off-by: Rolain Djeumen <[email protected]>
  • Loading branch information
uprightech committed Apr 15, 2024
1 parent 0b5e16b commit 977670c
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,5 @@ public String getExtraHttpParameters() {
return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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);
}


Expand All @@ -338,7 +339,7 @@ protected void startLoginRequest(final HttpServletRequest request, final HttpSer
Function<ProfileRequestContext, RelyingPartyContext> 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<Principal> principals = ((BrowserSSOProfileConfiguration) profileConfiguration).getDefaultAuthenticationMethods(profileRequestContext);
acrs = principals.stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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<ProfileRequestContext,RelyingPartyContext> 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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<GluuVanillaTrustRelationship> 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);
}
}
}
12 changes: 12 additions & 0 deletions static/src/main/patches/017.oxauth-authn-global-config-gvt.patch
Original file line number Diff line number Diff line change
@@ -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 @@

<bean id="shibboleth.gluu.AuthResultReuseCondition" class="org.gluu.idp.externalauth.OxAuthReuseResultByAcr">
</bean>
+
+ <bean id="gluuVanillaTrustRelationshipService" class="org.gluu.idp.service.GluuVanillaTrustRelationshipService">
+ <constructor-arg name="configurationFactory" value="#{idpConfigurationFactory.instance()}"/>
+ </bean>
</beans>
32 changes: 32 additions & 0 deletions static/src/main/patches/018.add-gluu-custom-view-bean.patch
Original file line number Diff line number Diff line change
@@ -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 @@
<import resource="conditional:${idp.home}/conf/gluu-storage.xml"/>
<import resource="conditional:${idp.home}/conf/gluu-release-attributes.xml"/>
<import resource="conditional:${idp.home}/conf/gluu-populate-context.xml"/>
+ <import resource="conditional:${idp.home}/conf/gluu-custom-view-bean.xml"/>

</beans>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <bean id="shibboleth.CustomViewContext" class="org.gluu.idp.service.GluuCustomViewService">
+ <constructor-arg name="vanillaTrustRelationshipService" ref="gluuVanillaTrustRelationshipService"/>
+ </bean>
+</beans>
67 changes: 67 additions & 0 deletions static/src/main/patches/019.add-custom-view-context.patch
Original file line number Diff line number Diff line change
@@ -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")
<!DOCTYPE html>
<html>
<head>
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")
<!DOCTYPE html>
<html>
<head>
@@ -100,6 +102,22 @@
<p><strong>#springMessageText("idp.logout.complete", "The logout operation is complete, and no other services appear to have been accessed during this session.")</strong></p>
<!-- Complete the flow by adding a hidden iframe. -->
<iframe style="display:none" src="$flowExecutionUrl&_eventId=proceed"></iframe>
+
+ <!-- gluu logout redirect url -->
+ #if($gluuLogoutRedirectUrl)
+ <p>
+ <strong>
+ #springMessageText("idp.gluulogout.redirect-msg","You will be redirected shortly")
+ </strong>
+ </p>
+ <form id="f_logout_redirect" method="$gluuLogoutRedirectMethod" action="$gluuLogoutRedirectUrl">
+ <p>
+ <button class="button-secondary" type="submit" name="_gluu_action" value="redirect">
+ #springMessageText("idp.gluu.logout.button","Click here if it's taking too long")
+ </button>
+ </p>
+ </form>
+ #end
#end

<ul>
@@ -107,7 +125,18 @@
<li><a href="#springMessageText("idp.url.helpdesk", '#')">#springMessageText("idp.login.needHelp", "Need Help?")</a></li>
</ul>
</section>
-
+ #if($gluuLogoutRedirectUrl)
+ <script type="text/javascript">
+ function performRedirect() {
+
+ var redir_form = document.getElementById("f_logout_redirect");
+ if(redir_form != null) {
+ redir_form.submit();
+ }
+ }
+ setTimeout(performRedirect,5000); // 5 seconds , making sure the hidden iframe to complete the flow has run
+ </script>
+ #end
</main>
<footer class="footer">
<div class="cc">

0 comments on commit 977670c

Please sign in to comment.