Skip to content

Commit

Permalink
Merge remote-tracking branch 'real-pac4j/master' into master-pem
Browse files Browse the repository at this point in the history
Conflicts:
	pac4j-jwt/src/main/java/org/pac4j/jwt/credentials/authenticator/JwtAuthenticator.java
  • Loading branch information
Garry committed Jun 3, 2016
2 parents c7c8813 + 3c5862d commit 7063591
Show file tree
Hide file tree
Showing 172 changed files with 2,596 additions and 1,272 deletions.
94 changes: 47 additions & 47 deletions README-ADFS.txt
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
Using pac4j against Microsoft ADFS 2.0 / 3.0
--------------------------------------------
Follow these rules to successfully authenticate using Microsoft ADFS 2.0 / 3.0.
1. Entity ID
------------
Always specify an explicit Entity ID that does not contain any question mark. By default, pac4j uses the same Entity ID as the
AssertionConsumerService location, which contains the client's name as a parameter after a question mark. Unfortunately ADFS does not work
well with such IDs and starts an infinite redirection loop when A SAML message with such a message arrives.
This property is supported since pac4j 1.6.0.
Don't forget to change your metadata accordingly!
2. Maximum authentication time
------------------------------
pac4j has the default maximum time set to 1 hour while ADFS has it set to 8 hours. Therefore it can happen that ADFS sends
an assertion which is still valid on ADFS side but evaluated as invalid on pac4j side.
You can see the following error message:
org.pac4j.saml.exceptions.SAMLException: Authentication issue instant is too old or in the future
There are two possibilities how to make the values equal:
- Change the value in ADFS management console in the trust properties dialog.
- Change the value on pac4j side.
3. Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
---------------------------------------------------------------------------------
You must install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files into your JRE/JDK
running pac4j. If you don't do it, you may encounter errors like this:
ERROR [org.opensaml.xml.encryption.Decrypter] - <Error decrypting the encrypted data element>
org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size
ERROR [org.opensaml.xml.encryption.Decrypter] - <Failed to decrypt EncryptedData using either EncryptedData KeyInfoCredentialResolver or EncryptedKeyResolver + EncryptedKey KeyInfoCredentialResolver>
ERROR [org.opensaml.saml2.encryption.Decrypter] - <SAML Decrypter encountered an error decrypting element content>
Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files can be downloaded from Oracle's Java Download site.
4. Error "Subject NameID, BaseID and EncryptedID cannot be all null at the same time if there are no Subject Confirmations."
----------------------------------------------------------------------------------------------------------------------------
Make sure your SP declaration in ADFS Server has been configured to return "Name ID" attribute in its SAML responses.
Using pac4j against Microsoft ADFS 2.0 / 3.0
--------------------------------------------

Follow these rules to successfully authenticate using Microsoft ADFS 2.0 / 3.0.

1. Entity ID
------------
Always specify an explicit Entity ID that does not contain any question mark. By default, pac4j uses the same Entity ID as the
AssertionConsumerService location, which contains the client's name as a parameter after a question mark. Unfortunately ADFS does not work
well with such IDs and starts an infinite redirection loop when A SAML message with such a message arrives.

This property is supported since pac4j 1.6.0.

Don't forget to change your metadata accordingly!


2. Maximum authentication time
------------------------------

pac4j has the default maximum time set to 1 hour while ADFS has it set to 8 hours. Therefore it can happen that ADFS sends
an assertion which is still valid on ADFS side but evaluated as invalid on pac4j side.

You can see the following error message:
org.pac4j.saml.exceptions.SAMLException: Authentication issue instant is too old or in the future

There are two possibilities how to make the values equal:
- Change the value in ADFS management console in the trust properties dialog.
- Change the value on pac4j side.


3. Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
---------------------------------------------------------------------------------

You must install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files into your JRE/JDK
running pac4j. If you don't do it, you may encounter errors like this:

ERROR [org.opensaml.xml.encryption.Decrypter] - <Error decrypting the encrypted data element>
org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size
ERROR [org.opensaml.xml.encryption.Decrypter] - <Failed to decrypt EncryptedData using either EncryptedData KeyInfoCredentialResolver or EncryptedKeyResolver + EncryptedKey KeyInfoCredentialResolver>
ERROR [org.opensaml.saml2.encryption.Decrypter] - <SAML Decrypter encountered an error decrypting element content>

Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files can be downloaded from Oracle's Java Download site.


4. Error "Subject NameID, BaseID and EncryptedID cannot be all null at the same time if there are no Subject Confirmations."
----------------------------------------------------------------------------------------------------------------------------
Make sure your SP declaration in ADFS Server has been configured to return "Name ID" attribute in its SAML responses.
This attribute is required by SAML pac4j but not included by default by ADFS.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img src="https://pac4j.github.io/pac4j/img/logo.png" width="300" />
</p>

`pac4j` is an **easy** and **powerful Java security engine** to authenticate users, get their profiles and manage authorizations in order to secure a Java web application. It provides a very comprehensive [security model](#main-concepts) and [implementation guidelines](https://github.com/pac4j/pac4j/wiki/Implement-pac4j-for-a-new-framework---tool). It is based on Java 8 and available under the Apache 2 license.
`pac4j` is an **easy** and **powerful Java security engine** to authenticate users, get their profiles and manage authorizations in order to secure a Java web application. It provides a comprehensive set of [concepts and components](#main-concepts-and-components). It is based on Java 8 and available under the Apache 2 license.

It is currently **available for most [frameworks / tools](#frameworks--tools-implementing-pac4j)** and **supports most [authentication](https://github.com/pac4j/pac4j/wiki/Clients) / [authorization](https://github.com/pac4j/pac4j/wiki/Authorizers) mechanisms**.

Expand All @@ -25,21 +25,21 @@ It is currently **available for most [frameworks / tools](#frameworks--tools-imp
| [SSO CAS server](https://github.com/Jasig/cas) | [cas-server-support-pac4j](http://jasig.github.io/cas/4.1.x/integration/Delegate-Authentication.html) | [cas-pac4j-oauth-demo](https://github.com/leleuj/cas-pac4j-oauth-demo)
| [Knox gateway for Hadoop](https://knox.apache.org) | [gateway-provider-security-pac4j](http://knox.apache.org/books/knox-0-8-0/user-guide.html#Pac4j+Provider+-+CAS+/+OAuth+/+SAML+/+OpenID+Connect) | [knox-pac4j-demo](https://github.com/pac4j/knox-pac4j-demo)

You can even implement `pac4j` for a new framework / tool by following these [guidelines](https://github.com/pac4j/pac4j/wiki/Implement-pac4j-for-a-new-framework---tool).
You can implement `pac4j` for a new framework / tool by following these [guidelines](https://github.com/pac4j/pac4j/wiki/How-to-implement-pac4j-for-a-new-framework---tool).

## Main concepts:

*In the pac4j project:*
## Main concepts and components:

1) A [**client**](https://github.com/pac4j/pac4j/wiki/Clients) represents an authentication mechanism. It performs the login process and returns a user profile. An indirect client is for UI authentication while a direct client is for web services authentication

2) An [**authorizer**](https://github.com/pac4j/pac4j/wiki/Authorizers) is meant to check authorizations on the authenticated user profile(s) or on the current web context

*In a pac4j implementation:*
3) A [**matcher**](https://github.com/pac4j/pac4j/wiki/Matchers) defines whether the security must apply on a specific url

4) The ["**security filter**"](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/engine/DefaultSecurityLogic.java) (or whatever the mechanism used to intercept HTTP requests) protects an url by checking that the user is authenticated and that the authorizations are valid, according to the clients and authorizers configuration. If the user is not authenticated, it performs authentication for direct clients or starts the login process for indirect clients

3) The "**security filter**" (or whatever the mechanism used to intercept HTTP requests) protects an url by checking that the user is authenticated and that the authorizations are checked, according to the clients and authorizers configuration. If the user is not authenticated, it performs authentication for direct clients or starts the login process for indirect clients
5) The ["**callback controller**"](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/engine/DefaultCallbackLogic.java) finishes the login process for an indirect client

4) The "**callback controller**" finishes the login process for an indirect client
6) The [**application logout controller**"](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/engine/DefaultApplicationLogoutLogic.java) logs out the user from the application.


## Versions
Expand All @@ -56,7 +56,7 @@ mvn clean install

The latest released version is the [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.pac4j/pac4j/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/org.pac4j/pac4j), available in the [Maven central repository](http://search.maven.org/#search%7Cga%7C1%7Cpac4j-). See the [release notes](https://github.com/pac4j/pac4j/wiki/Versions).

Read the [Javadoc](http://www.pac4j.org/apidocs/pac4j/1.8.7/index.html) and the [technical components](https://github.com/pac4j/pac4j/wiki/Technical-components) documentation for more information.
Read the [Javadoc](http://www.pac4j.org/apidocs/pac4j/1.8.8/index.html) and the [technical components](https://github.com/pac4j/pac4j/wiki/Technical-components) documentation for more information.


## Need help?
Expand Down
8 changes: 4 additions & 4 deletions pac4j-cas/src/main/java/org/pac4j/cas/client/CasClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.pac4j.core.context.J2EContext;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.CredentialsException;
import org.pac4j.core.exception.RequiresHttpAction;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.slf4j.Logger;
Expand Down Expand Up @@ -237,7 +237,7 @@ protected void initializeCas10Protocol() {
}

@Override
protected CasCredentials retrieveCredentials(final WebContext context) throws RequiresHttpAction {
protected CasCredentials retrieveCredentials(final WebContext context) throws HttpAction {

// like the SingleSignOutFilter from CAS client :
if (this.logoutHandler.isTokenRequest(context)) {
Expand All @@ -252,7 +252,7 @@ protected CasCredentials retrieveCredentials(final WebContext context) throws Re
this.logoutHandler.destroySession(context);
final String message = "logout request: no credential returned";
logger.debug(message);
throw RequiresHttpAction.ok(message, context);
throw HttpAction.ok(message, context);
}

if (this.gateway) {
Expand All @@ -265,7 +265,7 @@ protected CasCredentials retrieveCredentials(final WebContext context) throws Re
}

@Override
protected CasProfile retrieveUserProfile(final CasCredentials credentials, final WebContext context) throws RequiresHttpAction {
protected CasProfile retrieveUserProfile(final CasCredentials credentials, final WebContext context) throws HttpAction {
final String ticket = credentials.getServiceTicket();
try {
final Assertion assertion = this.ticketValidator.validate(ticket, computeFinalCallbackUrl(context));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.pac4j.core.client.IndirectClient;
import org.pac4j.core.client.RedirectAction;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.RequiresHttpAction;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.slf4j.Logger;
Expand Down Expand Up @@ -65,12 +65,12 @@ protected void internalInit(final WebContext context) {
}

@Override
protected RedirectAction retrieveRedirectAction(final WebContext context) throws RequiresHttpAction {
protected RedirectAction retrieveRedirectAction(final WebContext context) throws HttpAction {
throw new TechnicalException("Not supported by the CAS proxy receptor");
}

@Override
protected CasCredentials retrieveCredentials(final WebContext context) throws RequiresHttpAction {
protected CasCredentials retrieveCredentials(final WebContext context) throws HttpAction {

// like CommonUtils.readAndRespondToProxyReceptorRequest in CAS client
final String proxyGrantingTicketIou = context.getRequestParameter(PARAM_PROXY_GRANTING_TICKET_IOU);
Expand All @@ -81,7 +81,7 @@ protected CasCredentials retrieveCredentials(final WebContext context) throws Re
if (CommonUtils.isBlank(proxyGrantingTicket) || CommonUtils.isBlank(proxyGrantingTicketIou)) {
context.writeResponseContent("");
final String message = "Missing proxyGrantingTicket or proxyGrantingTicketIou";
throw RequiresHttpAction.ok(message, context);
throw HttpAction.ok(message, context);
}

this.proxyGrantingTicketStorage.save(proxyGrantingTicketIou, proxyGrantingTicket);
Expand All @@ -91,11 +91,11 @@ protected CasCredentials retrieveCredentials(final WebContext context) throws Re

final String message = "No credential for CAS proxy receptor -> returns ok";
logger.debug(message);
throw RequiresHttpAction.ok(message, context);
throw HttpAction.ok(message, context);
}

@Override
protected CasProfile retrieveUserProfile(final CasCredentials credentials, final WebContext context) throws RequiresHttpAction {
protected CasProfile retrieveUserProfile(final CasCredentials credentials, final WebContext context) throws HttpAction {
throw new TechnicalException("Not supported by the CAS proxy receptor");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.Pac4jConstants;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.RequiresHttpAction;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.credentials.UsernamePasswordCredentials;
import org.pac4j.core.credentials.authenticator.Authenticator;
Expand Down Expand Up @@ -66,7 +66,7 @@ protected void internalInit(final WebContext context) {
}

@Override
public void validate(final UsernamePasswordCredentials credentials) throws RequiresHttpAction {
public void validate(final UsernamePasswordCredentials credentials) throws HttpAction {
if (credentials == null || credentials.getPassword() == null || credentials.getUsername() == null) {
throw new TechnicalException("Credentials are required");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.junit.Test;
import org.pac4j.cas.credentials.CasCredentials;
import org.pac4j.core.context.MockWebContext;
import org.pac4j.core.exception.RequiresHttpAction;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.util.TestsConstants;
import org.pac4j.core.util.TestsHelper;

Expand Down Expand Up @@ -74,7 +74,7 @@ public void testInitCallbackUrlResolver() {
}

@Test
public void testRenew() throws RequiresHttpAction {
public void testRenew() throws HttpAction {
final CasClient casClient = new CasClient();
casClient.setCallbackUrl(CALLBACK_URL);
casClient.setCasLoginUrl(LOGIN_URL);
Expand All @@ -89,7 +89,7 @@ public void testRenew() throws RequiresHttpAction {
}

@Test
public void testGateway() throws RequiresHttpAction {
public void testGateway() throws HttpAction {
final CasClient casClient = new CasClient();
casClient.setCallbackUrl(CALLBACK_URL);
casClient.setCasLoginUrl(LOGIN_URL);
Expand All @@ -113,7 +113,7 @@ public void testLogout() {
casClient.init(null);
final MockWebContext context = MockWebContext.create().addRequestParameter("logoutRequest", logoutRequest)
.setRequestMethod("POST");
TestsHelper.expectException(() -> casClient.getCredentials(context), RequiresHttpAction.class, "logout request: no credential returned");
TestsHelper.expectException(() -> casClient.getCredentials(context), HttpAction.class, "logout request: no credential returned");
assertEquals(200, context.getResponseStatus());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.junit.Test;
import org.pac4j.core.context.MockWebContext;
import org.pac4j.core.exception.RequiresHttpAction;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.util.TestsConstants;
import org.pac4j.core.util.TestsHelper;

Expand Down Expand Up @@ -37,7 +37,7 @@ public void testMissingPgt() {
final MockWebContext context = MockWebContext.create();
try {
client.getCredentials(context.addRequestParameter(CasProxyReceptor.PARAM_PROXY_GRANTING_TICKET, VALUE));
} catch (final RequiresHttpAction e) {
} catch (final HttpAction e) {
assertEquals(200, context.getResponseStatus());
assertEquals("", context.getResponseContent());
assertEquals("Missing proxyGrantingTicket or proxyGrantingTicketIou", e.getMessage());
Expand All @@ -49,7 +49,7 @@ public void testMissingPgtiou() {
final CasProxyReceptor client = new CasProxyReceptor();
client.setCallbackUrl(CALLBACK_URL);
final MockWebContext context = MockWebContext.create();
TestsHelper.expectException(() -> client.getCredentials(context.addRequestParameter(CasProxyReceptor.PARAM_PROXY_GRANTING_TICKET_IOU, VALUE)), RequiresHttpAction.class,
TestsHelper.expectException(() -> client.getCredentials(context.addRequestParameter(CasProxyReceptor.PARAM_PROXY_GRANTING_TICKET_IOU, VALUE)), HttpAction.class,
"Missing proxyGrantingTicket or proxyGrantingTicketIou");
assertEquals(200, context.getResponseStatus());
assertEquals("", context.getResponseContent());
Expand All @@ -62,7 +62,7 @@ public void testOk() {
final MockWebContext context = MockWebContext.create()
.addRequestParameter(CasProxyReceptor.PARAM_PROXY_GRANTING_TICKET, VALUE)
.addRequestParameter(CasProxyReceptor.PARAM_PROXY_GRANTING_TICKET_IOU, VALUE);
TestsHelper.expectException(() -> client.getCredentials(context), RequiresHttpAction.class, "No credential for CAS proxy receptor -> returns ok");
TestsHelper.expectException(() -> client.getCredentials(context), HttpAction.class, "No credential for CAS proxy receptor -> returns ok");
assertEquals(200, context.getResponseStatus());
assertTrue(context.getResponseContent().length() > 0);
}
Expand Down

0 comments on commit 7063591

Please sign in to comment.