Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shibboleth 5.1.x Support #10

Merged
merged 4 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
35 changes: 15 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## NOTE Documentation and release artifacts are being worked on. As such documenatation and/or artifacts may not match, we thank you for your patience!

## A Shibboleth IdP v4.X plugin for delegating authentication to an external SSO Server using the CAS protocol
## A Shibboleth IdP v5.X plugin for delegating authentication to an external SSO Server using the CAS protocol


This is a Shibboleth IdP external authentication plugin that delegates primary authentication to an external
Expand All @@ -22,7 +22,7 @@ Also, please do note that the Shibboleth IdP v3x+ has support for the CAS protoc
Software Requirements
-------------------------------------------------------------

This minimum supported version of Shibboleth Identity Provider is `4.3.0`.
This minimum supported version of Shibboleth Identity Provider is `5.1.0`.
See [releases](https://github.com/Unicon/shib-cas-authn/releases) to find the the appropriate version.


Expand All @@ -35,9 +35,8 @@ Installation
- Copy the no-conversation-state.jsp file (also found inside this repo in IDP_HOME/edit-webapp) to your IdP's `IDP_HOME/edit-webapp`
- Copy two included jar files (`cas-client-core-x.x.x.jar` and `shib-casuathenticator-x.x.x.jar`) into the `IDP_HOME/edit-webapp/WEB-INF/lib`.
- Copy and Update the IdP's `web.xml`.
- Update the IdP's `external-authn.xml` file.
- (Optional) Update the IdP's `general-authn.xml` file.
- Update the IdP's `idp.properties` file.
- Update the IdP's `global.xml` file.
- Update the IdP's `authn.properties` file.
- Rebuild the war file.

**NOTE:** You should **ALWAYS** refers to the `README.md` file that is [packaged with the release](https://github.com/Unicon/shib-cas-authn/releases) for instructions.
Expand All @@ -64,9 +63,9 @@ Example snippet `web.xml`:
...
```

#### Update the IdP's external-authn.xml file
#### Update the IdP's global.xml file

In the `IDP_HOME/authn/external-authn.xml` file, ensure the context path points to `Authn/External` as shown below.
In the `IDP_HOME/conf/global.xml` file, ensure the context path points to `Authn/External` as shown below.

```xml
<!-- Servlet context-relative path to wherever your implementation lives. -->
Expand All @@ -75,21 +74,10 @@ In the `IDP_HOME/authn/external-authn.xml` file, ensure the context path points
```


#### OPTIONAL Update the IdP's general-authn.xml file

You may also need to ensure the `authn/External` flow is able to accept passive and forced authentication if you wish to use those features. The `authn/External` bean is modified in the `IDP_HOME/authn/general-authn.xml` file as shown below. Note that non browser flow is not possible or supported so it should be false.
#### Update the IdP's authn.properties file

```xml
<bean id="authn/External" parent="shibboleth.AuthenticationFlow"
p:passiveAuthenticationSupported="true"
p:forcedAuthenticationSupported="true"
p:nonBrowserSupported="false" />
```


#### Update the IdP's idp.properties file

1. Set the `idp.authn.flows` to `External` in `IDP_HOME/conf/idp.properties`. Or, for advance cases, add `External` to the list if you have others.
1. Set the `idp.authn.flows` to `External` in `IDP_HOME/conf/authn/authn.properties`. Or, for advance cases, add `External` to the list if you have others.
1. Add new properties for the ShibCas plugin.

```properties
Expand Down Expand Up @@ -118,6 +106,13 @@ shibcas.serverName = https://shibserver.example.edu
# Specify if the Relying Party/Service Provider entityId should be appended as a separate entityId query string parameter
# or embedded in the "service" querystring parameter - `append` (default) or `embed`
# shibcas.entityIdLocation = append
...
idp.authn.Password.passiveAuthenticationSupported = true
idp.authn.Password.forcedAuthenticationSupported = true
...
idp.authn.External.nonBrowserSupported = false


...
```

Expand Down
12 changes: 6 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ apply plugin: 'maven-publish'

defaultTasks 'clean', 'distZip', 'distTar'

sourceCompatibility = 11
targetCompatibility = 11
sourceCompatibility = 17
targetCompatibility = 17

group = 'net.unicon'
version = project.version
Expand All @@ -27,24 +27,24 @@ configurations {
configurations.implementation.transitive = false

dependencies {
implementation "org.jasig.cas.client:cas-client-core:$project.casClientVersion"
implementation "org.apereo.cas.client:cas-client-core:$project.casClientVersion"

compileOnly "javax.servlet:javax.servlet-api:$project.servletVersion"
compileOnly "jakarta.servlet:jakarta.servlet-api:$project.servletVersion"
compileOnly "net.shibboleth.idp:idp-authn-api:$project.shibIdpVersion"
compileOnly "net.shibboleth.idp:idp-saml-api:$project.shibIdpVersion"
compileOnly "org.apache.commons:commons-lang3:$project.commonLangVersion"

testImplementation "junit:junit:$project.junitVersion"
testImplementation "net.shibboleth.idp:idp-authn-api:$project.shibIdpVersion"
testImplementation "net.shibboleth.idp:idp-saml-api:$project.shibIdpVersion"
testImplementation "javax.servlet:javax.servlet-api:$project.servletVersion"
testImplementation "jakarta.servlet:jakarta.servlet-api:$project.servletVersion"
testImplementation "org.mockito:mockito-core:$project.mockitoVersion"
testImplementation "org.powermock:powermock-api-mockito2:$project.powermockVersion"
testImplementation "org.powermock:powermock-module-junit4:$project.powermockVersion"
}

test {
jvmArgs "--add-opens", "java.base/java.lang=ALL-UNNAMED"
jvmArgs "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED"
}

distributions {
Expand Down
10 changes: 6 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
version=4.3.1
version=5.0.0

casClientVersion=3.6.4
casClientVersion=4.0.3
commonLangVersion=3.11
junitVersion=4.13.1
mockitoVersion=3.6.28
powermockVersion=2.0.9
servletVersion=4.0.1
shibIdpVersion=4.3.1
servletVersion=6.0.0
shibIdpVersion=5.0.0
org.gradle.jvmargs=-Xmx1536M \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.security.Principal;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.unicon.idp.authn.provider.extra;

import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;

/**
* This interface defines the interface a custom parameter builder must adopt. The implementing class needs to build a single string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import net.shibboleth.idp.authn.principal.UsernamePrincipal;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.apereo.cas.client.authentication.AttributePrincipal;
import org.apereo.cas.client.validation.Assertion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.security.auth.Subject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactory;
import net.shibboleth.idp.authn.principal.PrincipalSupportingComponent;
import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.Assertion;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.saml2.core.AuthnContext;
import org.slf4j.Logger;
Expand All @@ -17,8 +17,8 @@

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashSet;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package net.unicon.idp.externalauth;

import org.jasig.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.Assertion;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
* This interface defines the public interface for a class that will translate the information from CAS to Shib. The translator
Expand Down
37 changes: 19 additions & 18 deletions src/main/java/net/unicon/idp/externalauth/ShibcasAuthServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
import net.unicon.idp.authn.provider.extra.EntityIdParameterBuilder;
import net.unicon.idp.authn.provider.extra.IParameterBuilder;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas10TicketValidator;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import org.apereo.cas.client.util.CommonUtils;
import org.apereo.cas.client.util.WebUtils;
import org.apereo.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.Cas10TicketValidator;
import org.apereo.cas.client.validation.Cas20ServiceTicketValidator;
import org.apereo.cas.client.validation.Cas30ServiceTicketValidator;
import org.apereo.cas.client.validation.TicketValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
Expand All @@ -21,13 +22,13 @@
import org.springframework.core.env.Environment;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
Expand Down Expand Up @@ -64,8 +65,8 @@ public class ShibcasAuthServlet extends HttpServlet {
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
// TODO: We have the opportunity to give back more to Shib than just the PRINCIPAL_NAME_KEY. Identify additional information
try {
final String ticket = CommonUtils.safeGetParameter(request, artifactParameterName);
final String gatewayAttempted = CommonUtils.safeGetParameter(request, "gatewayAttempted");
final String ticket = WebUtils.safeGetParameter(request, artifactParameterName);
final String gatewayAttempted = WebUtils.safeGetParameter(request, "gatewayAttempted");
final String authenticationKey = ExternalAuthentication.startExternalAuthentication(request);
final boolean force = Boolean.parseBoolean(request.getAttribute(ExternalAuthentication.FORCE_AUTHN_PARAM).toString());
final boolean passive = Boolean.parseBoolean(request.getAttribute(ExternalAuthentication.PASSIVE_AUTHN_PARAM).toString());
Expand Down Expand Up @@ -263,7 +264,7 @@ private void buildTranslators(final Environment environment) {
* Use the CAS CommonUtils to build the CAS Service URL.
*/
protected String constructServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
String serviceUrl = CommonUtils.constructServiceUrl(request, response, null, serverName,
String serviceUrl = WebUtils.constructServiceUrl(request, response, null, serverName,
serviceParameterName, artifactParameterName, true);

if ("embed".equalsIgnoreCase(entityIdLocation)) {
Expand All @@ -289,7 +290,7 @@ protected String constructServiceUrl(final HttpServletRequest request, final Htt
if(!requestEntityIdLocation.equals(relayingPartyId)) {
throw new TicketValidationException(String.format("Validation failed. relayingPartyId attribute request %s doesn't match with entityId request parameter %s", relayingPartyId, requestEntityIdLocation));
}
return CommonUtils.constructServiceUrl(request, response, null, serverName, serviceParameterName, artifactParameterName, true);
return WebUtils.constructServiceUrl(request, response, null, serverName, serviceParameterName, artifactParameterName, true);
}
return constructServiceUrl(request, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import net.shibboleth.idp.authn.ExternalAuthentication;
import net.shibboleth.idp.authn.ExternalAuthenticationException;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import org.apereo.cas.client.authentication.AttributePrincipal;
import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.Cas20ServiceTicketValidator;
import org.apereo.cas.client.validation.Cas30ServiceTicketValidator;
import org.apereo.cas.client.validation.TicketValidationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
Expand All @@ -20,11 +20,11 @@
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
Expand Down
Loading