Skip to content

Commit

Permalink
Migrate clients to V2 (#799)
Browse files Browse the repository at this point in the history
* GAE

* start OpenID

* finish OpenID + AnonymousClient

* SAML

* switch V1 <-> V2

* remove DirectClientV1

* remove IndirectClient V1

* refactor IndirectClient / DirectClient

* doc

* add missing init in SAML2Authenticator

* update doc
  • Loading branch information
leleuj committed Jan 20, 2017
1 parent 9144866 commit 8b36361
Show file tree
Hide file tree
Showing 66 changed files with 805 additions and 884 deletions.
11 changes: 6 additions & 5 deletions documentation/docs/clients.md
Expand Up @@ -38,7 +38,7 @@ Clients are of two kinds: direct for web services authentication and indirect fo
| | Direct clients = web services authentication | Indirect clients = UI authentication
|------|----------------|-----------------
| [Authentication flows](authentication-flows.html) | 1) Credentials are passed for each HTTP request (to the "[security filter](how-to-implement-pac4j-for-a-new-framework.html#a-secure-an-url)") | 1) The originally requested url is saved in session (by the "security filter")<br />2) The user is redirected to the identity provider (by the "security filter")<br />3) Authentication happens at the identity provider (or locally for the `FormClient` and the `IndirectBasicAuthClient`)<br />4) The user is redirected back to the callback endpoint / url ("callback filter")<br />5) The user is redirected to the originally requested url (by the "[callback filter](how-to-implement-pac4j-for-a-new-framework.html#b-handle-callback-for-indirect-client)") |
| How many times the login process occurs? | The authentication happens for every HTTP request (in the "security filter") via the defined [`Authenticator`](/dcos/authenticators.html) and `ProfileCreator`.<br />For performance reasons, a cache may be used by wrapping the current `Authenticator` in a `LocalCachingAuthenticator` or the user profile can be saved (by the `Authenticator` or `ProfileCreator`) into the web session using the available web context and the `ProfileManager` class | The authentication happens only once (in the "callback filter") |
| How many times the login process occurs? | The authentication happens for every HTTP request (in the "security filter") via the defined [`Authenticator`](/docs/authenticators.html) and `ProfileCreator`.<br />For performance reasons, a cache may be used by wrapping the current `Authenticator` in a `LocalCachingAuthenticator` or the user profile can be saved (by the `Authenticator` or `ProfileCreator`) into the web session using the available web context and the `ProfileManager` class | The authentication happens only once (in the "callback filter") |
| Where is the user profile saved by default? | In the HTTP request (stateless) | In the web session (statefull) |
| Where are the credentials? | Passed for every HTTP request (processed by the "security filter") | On the callback endpoint returned by the identity provider (and retrieved by the "callback filter") |
| Are the credentials mandatory? | Generally, no. If no credentials are provided, the direct client will be ignored (by the "security filter") | Generally, yes. Credentials are expected on the callback endpoint |
Expand Down Expand Up @@ -144,11 +144,12 @@ The `Client` interface has the following methods:

| Method | Usage |
|--------|-------|
| `HttpAction redirect(WebContext context) throws HttpAction` (only for indirect clients) | It redirects the user to the identity provider for login.<br />The redirection of the user to the identity provider can be defined via a [`RedirectActionBuilder`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/redirect/RedirectActionBuilder.java) |
| `C getCredentials(WebContext context) throws HttpAction` | It extracts the credentials from the HTTP request and validates them.<br />The extraction of the credentials can be done by a [`CredentialsExtractor`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/extractor/CredentialsExtractor.java) while the credentials validation is ensured by an [`Authenticator`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/authenticator/Authenticator.java) |
| `U getUserProfile(C credentials, WebContext context) throws HttpAction` | It builds the authenticated user profile.<br />The creation of the authenticated user profile can be performed by a [`ProfileCreator`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/profile/creator/ProfileCreator.java) |
| `HttpAction redirect(WebContext context) throws HttpAction` (only for indirect clients) | It redirects the user to the identity provider for login.<br />The redirection of the user to the identity provider is defined via a [`RedirectActionBuilder`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/redirect/RedirectActionBuilder.java) |
| `C getCredentials(WebContext context) throws HttpAction` | It extracts the credentials from the HTTP request and validates them.<br />The extraction of the credentials are done by a [`CredentialsExtractor`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/extractor/CredentialsExtractor.java) while the credentials validation is ensured by an [`Authenticator`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/authenticator/Authenticator.java) |
| `U getUserProfile(C credentials, WebContext context) throws HttpAction` | It builds the authenticated user profile.<br />The creation of the authenticated user profile is performed by a [`ProfileCreator`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/profile/creator/ProfileCreator.java) |
| `RedirectAction getLogoutAction(WebContext context, U currentProfile, String targetUrl)` | It returns the redirect action to call the identity provider logout.<br />The logout redirect aciton computation is done by a [`LogoutActionBuilder`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/logout/LogoutActionBuilder.java) |
{:.table-striped}

<br />

Clients are generally populated with default sub-components: `RedirectActionBuilder`, `CredentialsExtractor`, `ProfileCreator` and `Authenticator`, except for HTTP clients where the `Authenticator` must be defined. Sub-components can of course be changed for various [customizations](customizations.html).
Clients are generally populated with default sub-components: `RedirectActionBuilder`, `CredentialsExtractor`, `ProfileCreator`, `LogoutActionBuilder` and `Authenticator`, except for HTTP clients where the `Authenticator` must be defined. Sub-components can of course be changed for various [customizations](customizations.html).
4 changes: 2 additions & 2 deletions documentation/docs/customizations.md
Expand Up @@ -10,7 +10,7 @@ title: Customizations&#58;

Be sure to clearly understand what the roles of the different components are:

- a [`Client`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/client/Client.java) is a whole login process: it is indirect for UI ([`IndirectClientV2`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/client/IndirectClientV2.java)) and direct for web services ([`DirectClientV2`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/client/DirectClientV2.java). It redirects to the identity provider (indirect client only), extracts the user credentials, validates the user credentials and creates a user profile for the authenticated user
- a [`Client`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/client/Client.java) is a whole login process: it is indirect for UI ([`IndirectClient`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/client/IndirectClient.java)) and direct for web services ([`DirectClient`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/client/DirectClient.java). It redirects to the identity provider (indirect client only), extracts the user credentials, validates the user credentials and creates a user profile for the authenticated user
- a [`RedirectActionBuilder`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/redirect/RedirectActionBuilder.java) redirects the user to the identity provider for login (indirect clients)
- a [`CredentialsExtractor`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/extractor/CredentialsExtractor.java) extracts the user credentials from the HTTP request (indirect and direct clients)
- an [`Authenticator`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/authenticator/Authenticator.java) validates the user credentials (indirect and direct clients)
Expand All @@ -25,7 +25,7 @@ Nonetheless, building a `Client` requires extra efforts. Notice that:

- you really need to understand what kind of authentication mechanism you want to support: is it for UI (credentials are provided only once and authentication almost always occurs at an external identity provider) or for web services (credentials are passed for every request)

- all clients should implement the `IndirectClientV2` interface and define the appropriate `RedirectActionBuilder`, `CredentialsExtractor`, `Authenticator` and `ProfileCreator` (and optional `LogoutActionBuilder`)
- all clients should implement the `IndirectClient` interface and define the appropriate `RedirectActionBuilder`, `CredentialsExtractor`, `Authenticator` and `ProfileCreator` (and optional `LogoutActionBuilder`)

- it may require to create a new [`Credentials`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/credentials/Credentials.java) type (if it is not a simple string designed by the `TokenCredentials` or a username / password designed by the `UsernamePasswordCredentials`). These new credentials may inherit from the base credentials of the supported protocol (like `OAuthCredentials`)

Expand Down
4 changes: 4 additions & 0 deletions documentation/docs/release-notes.md
Expand Up @@ -5,6 +5,7 @@ title: Release notes&#58;

**v2.0.0**:

- All clients are built using sub-components (`RedirectActionBuilder`, `CredentialsExtractor` , `Authenticator`, `ProfileCreator` and `LogoutActionBuilder`): the `IndirectClientV2` and `DirectClientV2` are renamed as `IndirectClient` and `DirectClient` (and the existing `IndirectClient` and `DirectClient` components are removed)
- The session renewal is properly handled by clients (and especially CAS)
- The `WebContext` directly relies on the `SessionStore` whose capabilities are upgraded to handle back-channel logout
- Caches are backed via a `Store` component
Expand All @@ -16,6 +17,9 @@ title: Release notes&#58;
- Only two `PasswordEncoder` wrappers are available: one for Spring Security Crypto, the other one for Shiro
- Added new matcher `PathMatcher` and deprecated `ExcludedPathMatcher`

**v1.9.5:**

- Various bug fixes

**v1.9.4**:

Expand Down
8 changes: 3 additions & 5 deletions pac4j-cas/src/main/java/org/pac4j/cas/client/CasClient.java
Expand Up @@ -7,7 +7,7 @@
import org.pac4j.core.logout.CasLogoutActionBuilder;
import org.pac4j.cas.logout.CasLogoutHandler;
import org.pac4j.cas.redirect.CasRedirectActionBuilder;
import org.pac4j.core.client.IndirectClientV2;
import org.pac4j.core.client.IndirectClient;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.profile.CommonProfile;
Expand All @@ -28,7 +28,7 @@
* @author Jerome Leleu
* @since 1.4.0
*/
public class CasClient extends IndirectClientV2<TokenCredentials, CommonProfile> {
public class CasClient extends IndirectClient<TokenCredentials, CommonProfile> {

private CasConfiguration configuration = new CasConfiguration();

Expand All @@ -39,9 +39,7 @@ public CasClient(final CasConfiguration configuration) {
}

@Override
protected void internalInit(final WebContext context) {
super.internalInit(context);

protected void clientInit(final WebContext context) {
CommonHelper.assertNotNull("configuration", configuration);
configuration.setCallbackUrlResolver(this.getCallbackUrlResolver());
configuration.init(context);
Expand Down
Expand Up @@ -3,7 +3,7 @@
import java.util.concurrent.TimeUnit;

import org.jasig.cas.client.util.CommonUtils;
import org.pac4j.core.client.IndirectClientV2;
import org.pac4j.core.client.IndirectClient;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.exception.HttpAction;
Expand All @@ -25,7 +25,7 @@
* @author Jerome Leleu
* @since 1.4.0
*/
public final class CasProxyReceptor extends IndirectClientV2<TokenCredentials, CommonProfile> {
public final class CasProxyReceptor extends IndirectClient<TokenCredentials, CommonProfile> {

private static final Logger logger = LoggerFactory.getLogger(CasProxyReceptor.class);

Expand All @@ -36,9 +36,7 @@ public final class CasProxyReceptor extends IndirectClientV2<TokenCredentials, C
public static final String PARAM_PROXY_GRANTING_TICKET = "pgtId";

@Override
protected void internalInit(final WebContext context) {
super.internalInit(context);

protected void clientInit(final WebContext context) {
CommonHelper.assertNotNull("store", this.store);

setRedirectActionBuilder(ctx -> { throw new TechnicalException("Not supported by the CAS proxy receptor"); });
Expand Down
Expand Up @@ -5,7 +5,7 @@
import org.pac4j.cas.client.CasProxyReceptor;
import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.cas.credentials.authenticator.CasAuthenticator;
import org.pac4j.core.client.DirectClientV2;
import org.pac4j.core.client.DirectClient;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.credentials.authenticator.Authenticator;
Expand Down Expand Up @@ -34,7 +34,7 @@
* @author Jerome Leleu
* @since 1.9.2
*/
public class DirectCasClient extends DirectClientV2<TokenCredentials, CommonProfile> {
public class DirectCasClient extends DirectClient<TokenCredentials, CommonProfile> {

private CasConfiguration configuration;

Expand Down Expand Up @@ -80,7 +80,7 @@ protected TokenCredentials retrieveCredentials(final WebContext context) throws
}

@Override
protected void internalInit(final WebContext context) {
protected void clientInit(final WebContext context) {
CommonHelper.assertNotNull("configuration", this.configuration);
CommonHelper.assertTrue(!configuration.isGateway(), "the DirectCasClient can not support gateway to avoid infinite loops");
configuration.init(context);
Expand Down
Expand Up @@ -5,7 +5,7 @@
import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.cas.config.CasProtocol;
import org.pac4j.cas.credentials.authenticator.CasAuthenticator;
import org.pac4j.core.client.DirectClientV2;
import org.pac4j.core.client.DirectClient;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.credentials.extractor.ParameterExtractor;
Expand All @@ -26,7 +26,7 @@
* @author Jerome Leleu
* @since 1.9.2
*/
public class DirectCasProxyClient extends DirectClientV2<TokenCredentials, CommonProfile> {
public class DirectCasProxyClient extends DirectClient<TokenCredentials, CommonProfile> {

private CasConfiguration configuration;

Expand All @@ -40,7 +40,7 @@ public DirectCasProxyClient(final CasConfiguration casConfiguration, final Strin
}

@Override
protected void internalInit(final WebContext context) {
protected void clientInit(final WebContext context) {
CommonHelper.assertNotNull("configuration", this.configuration);
CommonHelper.assertNotBlank("serviceUrl", this.serviceUrl);
// must be a CAS proxy protocol
Expand Down
Expand Up @@ -7,7 +7,7 @@
import org.pac4j.cas.profile.CasProfile;
import org.pac4j.cas.profile.CasRestProfile;
import org.pac4j.cas.util.HttpUtils;
import org.pac4j.core.client.DirectClientV2;
import org.pac4j.core.client.DirectClient;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.exception.TechnicalException;
Expand All @@ -31,7 +31,7 @@
* @author Misagh Moayyed
* @since 1.8.0
*/
public abstract class AbstractCasRestClient extends DirectClientV2<UsernamePasswordCredentials, CasRestProfile> {
public abstract class AbstractCasRestClient extends DirectClient<UsernamePasswordCredentials, CasRestProfile> {

public void destroyTicketGrantingTicket(final CasRestProfile profile) {
HttpURLConnection connection = null;
Expand Down
Expand Up @@ -46,7 +46,7 @@ public CasRestBasicAuthClient(final Authenticator authenticator,
}

@Override
protected void internalInit(final WebContext context) {
protected void clientInit(final WebContext context) {
CommonHelper.assertNotBlank("headerName", this.headerName);
CommonHelper.assertNotNull("prefixHeader", this.prefixHeader);

Expand Down
Expand Up @@ -44,7 +44,7 @@ public CasRestFormClient(final Authenticator authenticator, final String usernam
}

@Override
protected void internalInit(final WebContext context) {
protected void clientInit(final WebContext context) {
CommonHelper.assertNotBlank("usernameParameter", this.usernameParameter);
CommonHelper.assertNotBlank("passwordParameter", this.passwordParameter);

Expand Down

0 comments on commit 8b36361

Please sign in to comment.