diff --git a/README.md b/README.md index 145256416e..65a2d8332b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ It provides a comprehensive set of [**concepts and components**](http://www.pac4 [OAuth (Facebook, Twitter, Google...)](http://www.pac4j.org/docs/clients/oauth.html) - [SAML](http://www.pac4j.org/docs/clients/saml.html) - [CAS](http://www.pac4j.org/docs/clients/cas.html) - [OpenID Connect](http://www.pac4j.org/docs/clients/openid-connect.html) - [HTTP](http://www.pac4j.org/docs/clients/http.html) - [OpenID](http://www.pac4j.org/docs/clients/openid.html) - [Google App Engine](http://www.pac4j.org/docs/clients/google-app-engine.html) - [Kerberos (SPNEGO/Negotiate)](http://www.pac4j.org/docs/clients/kerberos.html) -[LDAP](http://www.pac4j.org/docs/authenticators/ldap.html) - [SQL](http://www.pac4j.org/docs/authenticators/sql.html) - [JWT](http://www.pac4j.org/docs/authenticators/jwt.html) - [MongoDB](http://www.pac4j.org/docs/authenticators/mongodb.html) - [CouchDB](http://www.pac4j.org/docs/authenticators/couchdb.html) - [IP address](http://www.pac4j.org/docs/authenticators/ip.html) +[LDAP](http://www.pac4j.org/docs/authenticators/ldap.html) - [SQL](http://www.pac4j.org/docs/authenticators/sql.html) - [JWT](http://www.pac4j.org/docs/authenticators/jwt.html) - [MongoDB](http://www.pac4j.org/docs/authenticators/mongodb.html) - [CouchDB](http://www.pac4j.org/docs/authenticators/couchdb.html) - [IP address](http://www.pac4j.org/docs/authenticators/ip.html) - [REST API](http://www.pac4j.org/docs/authenticators/rest.html) ## Authorization mechanisms: diff --git a/documentation/_includes/header.html b/documentation/_includes/header.html index a972c39c77..d3116aef3d 100644 --- a/documentation/_includes/header.html +++ b/documentation/_includes/header.html @@ -12,7 +12,7 @@ {% if page.url contains 'docs' %} {% endif %} - + Fork me on GitHub diff --git a/documentation/docs/authenticators.md b/documentation/docs/authenticators.md index e953bf59c7..e5f9bac4dd 100644 --- a/documentation/docs/authenticators.md +++ b/documentation/docs/authenticators.md @@ -14,7 +14,7 @@ This `Authenticator` interface has only one method: `void validate(C credentials The [`HttpAction`](https://github.com/pac4j/pac4j/blob/master/pac4j-core/src/main/java/org/pac4j/core/exception/HttpAction.java) allows you to interrupt the credentials validation and trigger a specific HTTP action (like a temporary redirection). -You can use various `Authenticator` for many identity systems: +You can use various `Authenticator` for many identity mechanisms: - [LDAP](authenticators/ldap.html) - [SQL](authenticators/sql.html) @@ -22,6 +22,7 @@ You can use various `Authenticator` for many identity systems: - [MongoDB](authenticators/mongodb.html) - [CouchDB](authenticators/couchdb.html) - [IP address](authenticators/ip.html) +- [REST API](authenticators/rest.html) ## 1) Deal with performance issues diff --git a/documentation/docs/authenticators/rest.md b/documentation/docs/authenticators/rest.md new file mode 100644 index 0000000000..3340ec6b98 --- /dev/null +++ b/documentation/docs/authenticators/rest.md @@ -0,0 +1,48 @@ +--- +layout: doc +title: REST API +--- + +*pac4j* allows you to validate users via a REST API. + +## 1) Dependency + +You need to use the following module: `pac4j-http`. + +**Example (Maven dependency):** + +```xml + + org.pac4j + pac4j-http + ${pac4j.version} + +``` + +## 2) `RestAuthenticator` + +The [`RestAuthenticator`](https://github.com/pac4j/pac4j/blob/master/pac4j-http/src/main/java/org/pac4j/http/credentials/authenticator/RestAuthenticator.java) validates the provided username/password by POSTing them as a basic authentication to an URL which must return: + +- a 200 HTTP response with a user profile as a JSON if the username/password credentials are valid + +- any other HTTP status code (preferably 401) if the username/password credentials are not valid. + +In case of a successful authentication, a [`RestProfile`](https://github.com/pac4j/pac4j/blob/master/pac4j-http/src/main/java/org/pac4j/http/profile/RestProfile.java) is returned. + +**Example of a correct server response:** + +```json +{ + "id": "1234", + "attributes": { + "firstName": "Jerome" + } +} +``` + +**Example of a client:** + +```java +RestAuthenticator authenticator = new RestAuthenticator("http://rest-api-url"); +DirectBasicAuthClient directBasicAuthClient = new DirectBasicAuthClient(authenticator); +``` diff --git a/documentation/docs/backward-compatibility.md b/documentation/docs/backward-compatibility.md index da0940836e..a6a67e161f 100644 --- a/documentation/docs/backward-compatibility.md +++ b/documentation/docs/backward-compatibility.md @@ -15,6 +15,9 @@ Given a version X.Y.Z: Generally, *pac4j* implementations will adopt the semver versioning when upgrading to `pac4j` version 2, if they don't already have. +
Notice that, while pac4j-* modules are backward compatible, you should always add the pac4j-core dependency in the same version as the upgraded pac4j-* dependency.
+ + ## 2) Maintenance Two stable and released streams of `pac4j` are maintained at the same time. diff --git a/documentation/docs/config.md b/documentation/docs/config.md index 64152274bf..296f9244ea 100644 --- a/documentation/docs/config.md +++ b/documentation/docs/config.md @@ -93,7 +93,9 @@ Here are the properties you can use to define the clients (, password encoders a | `encoder.shiro` (if no specific properties are required), `encoder.shiro.generatePublicSalt`, `encoder.shiro.hashAlgorithmName`, `encoder.shiro.hashIterations` and `encoder.shiro.privateSalt` | To define a `ShiroPasswordEncoder` based on the provided properties and named `encoder.shiro` or `encoder.shiro.N` | | `ldap.type`, `ldap.dnFormat`, `ldap.principalAttributes`,`ldap.principalAttributeId`, `ldap.principalAttributePassword`, `ldap.subtreeSearch`, `ldap.usersDn`, `ldap.userFilter`, `ldap.enhanceWithEntryResolver`, `ldap.trustCertificates`, `ldap.keystore`, `ldap.keystorePassword`, `ldap.keystoreType`, `ldap.minPoolSize`, `ldap.maxPoolSize`, `ldap.poolPassivator`, `ldap.validateOnCheckout`, `ldap.validatePeriodically`, `ldap.validatePeriod`, `ldap.failFast`, `ldap.idleTime`, `ldap.prunePeriod`, `ldap.blockWaitTime`, `ldap.url`, `ldap.useSsl`, `ldap.useStartTls`, `ldap.connectTimeout`, `ldap.providerClass`, `ldap.allowMultipleDns`, `ldap.bindDn`, `ldap.bindCredential`, `ldap.saslRealm`, `ldap.saslMechanism`, `ldap.saslAuthorizationId`, `ldap.saslSecurityStrength` and `ldap.saslQualityOfProtection` | To define a `LdapAuthenticator` based on the provided properties and named `ldap` or `ldap.N` | | `db.dataSourceClassName`, `db.jdbcUrl`, `db.userAttributes`, `db.userIdAttribute`, `db.usernameAttribute`, `db.userPasswordAttribute`, `db.usersTable`, `db.username`, `db.password`, `db.autoCommit`, `db.connectionTimeout`, `db.idleTimeout`, `db.maxLifetime`, `db.connectionTestQuery`, `db.minimumIdle`, `db.maximumPoolSize`, `db.poolName`, `db.initializationFailTimeout`, `db.isolateInternalQueries`, `db.allowPoolSuspension`, `db.readOnly`, `db.registerMbeans`, `db.catalog`, `db.connectionInitSql`, `db.driverClassName`, `db.transactionIsolation`, `db.validationTimeout`, `db.leakDetectionThreshold`, `db.customParamKey`, `db.customParamValue`, `db.loginTimeout`, `db.dataSourceJndi` and `db.passwordEncoder` | To define a `DbAuthenticator` based on the provided properties and named `db` or `db.N` | +| `rest.url` | To define a `RestAuthenticator` based on the provided properties and named `rest` or `rest.N` | | `anonymous` | To define the `AnonymousClient`, the value is ignored | +| `directBasicAuth.authenticator` | To define a `DirectBasicAuthClient` based on the provided properties | | `saml.keystorePassword`, `saml.privateKeyPassword`, `saml.keystorePath`, `saml.identityProviderMetadataPath`, `saml.maximumAuthenticationLifetime`, `saml.serviceProviderEntityId`, `saml.serviceProviderMetadataPath`, `saml.destinationBindingType` | To define a `SAML2Client` based on the provided properties | | `cas.loginUrl`, `cas.protocol` | To define a `CasClient` based on the provided properties | | `oidc.type` (`google` or `azure`), `oidc.id`, `oidc.secret`, `oidc.scope`, `oidc.discoveryUri`, `oidc.useNonce`, `oidc.preferredJwsAlgorithm`, `oidc.maxClockSkew`, `oidc.clientAuthenticationMethod`, `oidc.customParamKey1`, `oidc.customParamValue1`, `oidc.customParamKey2`,`oidc.customParamValue2` | To define an OpenID connect client based on the provided properties | diff --git a/documentation/docs/index.md b/documentation/docs/index.md index 4972d77338..f7d67efee7 100644 --- a/documentation/docs/index.md +++ b/documentation/docs/index.md @@ -9,7 +9,7 @@ title: The pac4j engine/cor ### ▸ [Clients](clients.html): [OAuth](clients/oauth.html) - [SAML](clients/saml.html) - [CAS](clients/cas.html) - [OpenID Connect](clients/openid-connect.html) - [HTTP](clients/http.html) - [OpenID](clients/openid.html) - [Google App Engine](clients/google-app-engine.html) - [Kerberos (SPNEGO)](clients/kerberos.html) -### ▸ [Authenticators](authenticators.html): [LDAP](authenticators/ldap.html) - [SQL](authenticators/sql.html) - [JWT](authenticators/jwt.html) - [MongoDB](authenticators/mongodb.html) - [CouchDB](authenticators/couchdb.html) - [IP address](authenticators/ip.html) +### ▸ [Authenticators](authenticators.html): [LDAP](authenticators/ldap.html) - [SQL](authenticators/sql.html) - [JWT](authenticators/jwt.html) - [MongoDB](authenticators/mongodb.html) - [CouchDB](authenticators/couchdb.html) - [IP address](authenticators/ip.html) - [REST API](authenticators/rest.html) ## 3) Authorization mechanisms: [Authorizers](authorizers.html) diff --git a/documentation/docs/release-notes.md b/documentation/docs/release-notes.md index 78644210d3..9284f090a7 100644 --- a/documentation/docs/release-notes.md +++ b/documentation/docs/release-notes.md @@ -9,6 +9,7 @@ title: Release notes: - Removed Stormpath support - The password encoders and LDAP/SQL authenticators can be defined via properties through the `PropertiesConfigFactory` - Supports CouchDB for authentication and user management +- REST API `Authenticator` - In case of an unauthorized AJAX request, the redirection URL to the identity server is added as the `Location` header to the 401 error **v2.0.0**: diff --git a/documentation/index.html b/documentation/index.html index 8c168a5bd0..7a1a5a0e6a 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -42,7 +42,7 @@

Available for most frameworks/tools (implementations):
Supports most authentication mechanisms:
OAuth (Facebook, Twitter, Google...) - SAML - CAS - OpenID Connect - HTTP - OpenID - Google App Engine
- LDAP - SQL - JWT - MongoDB - Stormpath - IP address - Kerberos (SPNEGO)
+ LDAP - SQL - JWT - MongoDB - CouchDB - IP address - Kerberos (SPNEGO) - REST API

and authorization mechanisms:
diff --git a/pac4j-cas/src/main/java/org/pac4j/cas/client/rest/AbstractCasRestClient.java b/pac4j-cas/src/main/java/org/pac4j/cas/client/rest/AbstractCasRestClient.java index 0c1c601a48..1666a8846c 100644 --- a/pac4j-cas/src/main/java/org/pac4j/cas/client/rest/AbstractCasRestClient.java +++ b/pac4j-cas/src/main/java/org/pac4j/cas/client/rest/AbstractCasRestClient.java @@ -6,7 +6,7 @@ import org.pac4j.cas.config.CasConfiguration; import org.pac4j.cas.profile.CasProfile; import org.pac4j.cas.profile.CasRestProfile; -import org.pac4j.cas.util.HttpUtils; +import org.pac4j.core.util.HttpUtils; import org.pac4j.core.client.DirectClient; import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.WebContext; diff --git a/pac4j-cas/src/main/java/org/pac4j/cas/credentials/authenticator/CasRestAuthenticator.java b/pac4j-cas/src/main/java/org/pac4j/cas/credentials/authenticator/CasRestAuthenticator.java index fce6c96795..137cd4ded9 100644 --- a/pac4j-cas/src/main/java/org/pac4j/cas/credentials/authenticator/CasRestAuthenticator.java +++ b/pac4j-cas/src/main/java/org/pac4j/cas/credentials/authenticator/CasRestAuthenticator.java @@ -1,7 +1,7 @@ package org.pac4j.cas.credentials.authenticator; import org.pac4j.cas.config.CasConfiguration; -import org.pac4j.cas.util.HttpUtils; +import org.pac4j.core.util.HttpUtils; import org.pac4j.cas.profile.CasRestProfile; import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.Pac4jConstants; diff --git a/pac4j-config/pom.xml b/pac4j-config/pom.xml index 4f840f127f..3b518e8d90 100644 --- a/pac4j-config/pom.xml +++ b/pac4j-config/pom.xml @@ -1,52 +1,52 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-config - jar - pac4j configuration + pac4j-config + jar + pac4j configuration - - - org.pac4j - pac4j-core - - - org.pac4j - pac4j-cas - true - - - org.pac4j - pac4j-saml - true - - - org.pac4j - pac4j-oauth - true - + + + org.pac4j + pac4j-core + + + org.pac4j + pac4j-cas + true + + + org.pac4j + pac4j-saml + true + + + org.pac4j + pac4j-oauth + true + org.pac4j pac4j-oidc - true - - - org.pac4j - pac4j-ldap - true - - - org.pac4j - pac4j-http - true - + true + + + org.pac4j + pac4j-ldap + true + + + org.pac4j + pac4j-http + true + com.zaxxer HikariCP @@ -68,22 +68,22 @@ true - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + org.pac4j pac4j-ldap @@ -107,23 +107,23 @@ ${h2.version} test - - + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.config - org.pac4j.config.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.config + org.pac4j.config.*;version=${project.version} + * + + + + + diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/AbstractBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/AbstractBuilder.java index 07cb3701eb..4bf5dccfa7 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/AbstractBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/AbstractBuilder.java @@ -1,5 +1,11 @@ package org.pac4j.config.builder; +import org.pac4j.config.client.PropertiesConstants; +import org.pac4j.core.credentials.authenticator.Authenticator; +import org.pac4j.http.credentials.authenticator.test.SimpleTestTokenAuthenticator; +import org.pac4j.http.credentials.authenticator.test.SimpleTestUsernamePasswordAuthenticator; + +import java.util.HashMap; import java.util.Map; /** @@ -8,7 +14,7 @@ * @author Jerome Leleu * @since 2.0.0 */ -public abstract class AbstractBuilder { +public abstract class AbstractBuilder implements PropertiesConstants { protected static final int MAX_NUM_CLIENTS = 10; protected static final int MAX_NUM_AUTHENTICATORS = 10; @@ -17,8 +23,16 @@ public abstract class AbstractBuilder { protected final Map properties; + protected final Map authenticators; + protected AbstractBuilder(final Map properties) { this.properties = properties; + this.authenticators = new HashMap<>(); + } + + protected AbstractBuilder(final Map properties, final Map authenticators) { + this.properties = properties; + this.authenticators = authenticators; } protected String concat(final String value, int num) { @@ -48,4 +62,14 @@ protected int getPropertyAsInteger(final String name, final int num) { protected long getPropertyAsLong(final String name, final int num) { return Long.parseLong(getProperty(name, num)); } + + protected Authenticator getAuthenticator(final String name) { + if (AUTHENTICATOR_TEST_TOKEN.equals(name)) { + return new SimpleTestTokenAuthenticator(); + } else if (AUTHENTICATOR_TEST_USERNAME_PASSWORD.equals(name)) { + return new SimpleTestUsernamePasswordAuthenticator(); + } else { + return authenticators.get(name); + } + } } diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/CasClientBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/CasClientBuilder.java index df12c9509d..8a6fe4a634 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/CasClientBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/CasClientBuilder.java @@ -3,7 +3,6 @@ import org.pac4j.cas.client.CasClient; import org.pac4j.cas.config.CasConfiguration; import org.pac4j.cas.config.CasProtocol; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.client.Client; import java.util.List; @@ -17,7 +16,7 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class CasClientBuilder extends AbstractBuilder implements PropertiesConstants { +public class CasClientBuilder extends AbstractBuilder { public CasClientBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/DbAuthenticatorBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/DbAuthenticatorBuilder.java index 0f2dbe87cb..7f4aa06707 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/DbAuthenticatorBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/DbAuthenticatorBuilder.java @@ -1,7 +1,6 @@ package org.pac4j.config.builder; import com.zaxxer.hikari.HikariDataSource; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.credentials.authenticator.Authenticator; import org.pac4j.core.credentials.password.PasswordEncoder; import org.pac4j.core.exception.TechnicalException; @@ -17,7 +16,7 @@ * @author Jerome Leleu * @since 2.1.0 */ -public class DbAuthenticatorBuilder extends AbstractBuilder implements PropertiesConstants { +public class DbAuthenticatorBuilder extends AbstractBuilder { public DbAuthenticatorBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/DirectClientBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/DirectClientBuilder.java index fac930e97d..a10c3c8846 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/DirectClientBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/DirectClientBuilder.java @@ -1,8 +1,9 @@ package org.pac4j.config.builder; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.client.Client; import org.pac4j.core.client.direct.AnonymousClient; +import org.pac4j.core.credentials.authenticator.Authenticator; +import org.pac4j.http.client.direct.DirectBasicAuthClient; import java.util.List; import java.util.Map; @@ -15,10 +16,10 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class DirectClientBuilder extends AbstractBuilder implements PropertiesConstants { +public class DirectClientBuilder extends AbstractBuilder { - public DirectClientBuilder(final Map properties) { - super(properties); + public DirectClientBuilder(final Map properties, final Map authenticators) { + super(properties, authenticators); } public void tryCreateAnonymousClient(final List clients) { @@ -27,4 +28,16 @@ public void tryCreateAnonymousClient(final List clients) { clients.add(new AnonymousClient()); } } + + public void tryCreateDirectBasciAuthClient(final List clients) { + for (int i = 0; i <= MAX_NUM_CLIENTS; i++) { + final String authenticator = getProperty(DIRECTBASICAUTH_AUTHENTICATOR, i); + if (isNotBlank(authenticator)) { + final DirectBasicAuthClient directBasicAuthClient = new DirectBasicAuthClient(); + directBasicAuthClient.setAuthenticator(getAuthenticator(authenticator)); + directBasicAuthClient.setName(concat(directBasicAuthClient.getName(), i)); + clients.add(directBasicAuthClient); + } + } + } } diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/IndirectHttpClientBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/IndirectHttpClientBuilder.java index 7b92944c98..f424db270a 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/IndirectHttpClientBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/IndirectHttpClientBuilder.java @@ -1,12 +1,9 @@ package org.pac4j.config.builder; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.client.Client; import org.pac4j.core.credentials.authenticator.Authenticator; import org.pac4j.http.client.indirect.FormClient; import org.pac4j.http.client.indirect.IndirectBasicAuthClient; -import org.pac4j.http.credentials.authenticator.test.SimpleTestTokenAuthenticator; -import org.pac4j.http.credentials.authenticator.test.SimpleTestUsernamePasswordAuthenticator; import java.util.List; import java.util.Map; @@ -19,13 +16,10 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class IndirectHttpClientBuilder extends AbstractBuilder implements PropertiesConstants { - - private final Map authenticators; +public class IndirectHttpClientBuilder extends AbstractBuilder { public IndirectHttpClientBuilder(final Map properties, final Map authenticators) { - super(properties); - this.authenticators = authenticators; + super(properties, authenticators); } public void tryCreateLoginFormClient(final List clients) { @@ -62,14 +56,4 @@ public void tryCreateIndirectBasciAuthClient(final List clients) { } } } - - protected Authenticator getAuthenticator(final String name) { - if (AUTHENTICATOR_TEST_TOKEN.equals(name)) { - return new SimpleTestTokenAuthenticator(); - } else if (AUTHENTICATOR_TEST_USERNAME_PASSWORD.equals(name)) { - return new SimpleTestUsernamePasswordAuthenticator(); - } else { - return authenticators.get(name); - } - } } diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/LdapAuthenticatorBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/LdapAuthenticatorBuilder.java index 42101e066c..d60d6121c1 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/LdapAuthenticatorBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/LdapAuthenticatorBuilder.java @@ -4,7 +4,6 @@ import org.ldaptive.sasl.Mechanism; import org.ldaptive.sasl.QualityOfProtection; import org.ldaptive.sasl.SecurityStrength; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.config.ldaptive.LdapAuthenticationProperties; import org.pac4j.config.ldaptive.LdaptiveAuthenticatorBuilder; import org.pac4j.core.credentials.authenticator.Authenticator; @@ -20,7 +19,7 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class LdapAuthenticatorBuilder extends AbstractBuilder implements PropertiesConstants { +public class LdapAuthenticatorBuilder extends AbstractBuilder { public LdapAuthenticatorBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/OAuthBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/OAuthBuilder.java index bed42276db..136eddb837 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/OAuthBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/OAuthBuilder.java @@ -1,6 +1,5 @@ package org.pac4j.config.builder; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.client.Client; import org.pac4j.oauth.client.*; @@ -15,7 +14,7 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class OAuthBuilder extends AbstractBuilder implements PropertiesConstants { +public class OAuthBuilder extends AbstractBuilder { public OAuthBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/OidcClientBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/OidcClientBuilder.java index 4a5a0f11f3..311928c28a 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/OidcClientBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/OidcClientBuilder.java @@ -2,7 +2,6 @@ import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.client.Client; import org.pac4j.oidc.client.AzureAdClient; import org.pac4j.oidc.client.GoogleOidcClient; @@ -20,7 +19,7 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class OidcClientBuilder extends AbstractBuilder implements PropertiesConstants { +public class OidcClientBuilder extends AbstractBuilder { public OidcClientBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/RestAuthenticatorBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/RestAuthenticatorBuilder.java new file mode 100644 index 0000000000..64d3ee8b39 --- /dev/null +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/RestAuthenticatorBuilder.java @@ -0,0 +1,30 @@ +package org.pac4j.config.builder; + +import org.pac4j.core.credentials.authenticator.Authenticator; +import org.pac4j.http.credentials.authenticator.RestAuthenticator; + +import java.util.Map; + +import static org.pac4j.core.util.CommonHelper.isNotBlank; + +/** + * Builder for the REST authenticator. + * + * @author Jerome Leleu + * @since 2.1.0 + */ +public class RestAuthenticatorBuilder extends AbstractBuilder { + + public RestAuthenticatorBuilder(final Map properties) { + super(properties); + } + + public void tryBuildRestAuthenticator(final Map authenticators) { + for (int i = 0; i <= MAX_NUM_AUTHENTICATORS; i++) { + final String url = getProperty(REST_URL, i); + if (isNotBlank(url)) { + authenticators.put(concat("rest", i), new RestAuthenticator(url)); + } + } + } +} diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/Saml2ClientBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/Saml2ClientBuilder.java index 4937ad3799..e0677a4dbe 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/Saml2ClientBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/Saml2ClientBuilder.java @@ -1,6 +1,5 @@ package org.pac4j.config.builder; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.client.Client; import org.pac4j.saml.client.SAML2Client; import org.pac4j.saml.client.SAML2ClientConfiguration; @@ -16,7 +15,7 @@ * @author Jerome Leleu * @since 2.0.0 */ -public class Saml2ClientBuilder extends AbstractBuilder implements PropertiesConstants { +public class Saml2ClientBuilder extends AbstractBuilder { public Saml2ClientBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/ShiroEncoderBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/ShiroEncoderBuilder.java index 04a4b8bdec..f5ab080501 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/ShiroEncoderBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/ShiroEncoderBuilder.java @@ -3,7 +3,6 @@ import org.apache.shiro.authc.credential.DefaultPasswordService; import org.apache.shiro.crypto.hash.DefaultHashService; import org.apache.shiro.util.ByteSource; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.credentials.password.PasswordEncoder; import org.pac4j.core.credentials.password.ShiroPasswordEncoder; @@ -17,7 +16,7 @@ * @author Jerome Leleu * @since 2.1.0 */ -public class ShiroEncoderBuilder extends AbstractBuilder implements PropertiesConstants { +public class ShiroEncoderBuilder extends AbstractBuilder { public ShiroEncoderBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/builder/SpringEncoderBuilder.java b/pac4j-config/src/main/java/org/pac4j/config/builder/SpringEncoderBuilder.java index 399b1f58c1..d51b80a993 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/builder/SpringEncoderBuilder.java +++ b/pac4j-config/src/main/java/org/pac4j/config/builder/SpringEncoderBuilder.java @@ -1,6 +1,5 @@ package org.pac4j.config.builder; -import org.pac4j.config.client.PropertiesConstants; import org.pac4j.core.credentials.password.SpringSecurityPasswordEncoder; import org.pac4j.core.exception.TechnicalException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -20,7 +19,7 @@ * @author Jerome Leleu * @since 2.1.0 */ -public class SpringEncoderBuilder extends AbstractBuilder implements PropertiesConstants { +public class SpringEncoderBuilder extends AbstractBuilder { public SpringEncoderBuilder(final Map properties) { super(properties); diff --git a/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConfigFactory.java b/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConfigFactory.java index 44dde4c77c..dc4c15adc7 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConfigFactory.java +++ b/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConfigFactory.java @@ -20,7 +20,7 @@ * @author Jerome Leleu * @since 1.8.1 */ -public class PropertiesConfigFactory extends AbstractBuilder implements ConfigFactory, PropertiesConstants { +public class PropertiesConfigFactory extends AbstractBuilder implements ConfigFactory { private final String callbackUrl; @@ -88,12 +88,16 @@ public Config build(final Object... parameters) { oidcClientBuilder.tryCreateOidcClient(clients); } // pac4j-http dependency required - if (hasHttpClients()) { + if (hasHttpAuthenticatorsOrClients()) { + final RestAuthenticatorBuilder restAuthenticatorBuilder = new RestAuthenticatorBuilder(properties); + restAuthenticatorBuilder.tryBuildRestAuthenticator(authenticators); + final IndirectHttpClientBuilder indirectHttpClientBuilder = new IndirectHttpClientBuilder(properties, authenticators); indirectHttpClientBuilder.tryCreateLoginFormClient(clients); indirectHttpClientBuilder.tryCreateIndirectBasciAuthClient(clients); - final DirectClientBuilder directClientBuilder = new DirectClientBuilder(properties); + final DirectClientBuilder directClientBuilder = new DirectClientBuilder(properties, authenticators); directClientBuilder.tryCreateAnonymousClient(clients); + directClientBuilder.tryCreateDirectBasciAuthClient(clients); } return new Config(callbackUrl, clients); } @@ -201,10 +205,15 @@ protected boolean hasOidcClients() { return false; } - protected boolean hasHttpClients() { + protected boolean hasHttpAuthenticatorsOrClients() { if (isNotBlank(getProperty(ANONYMOUS))) { return true; } + for (int i = 0; i <= MAX_NUM_AUTHENTICATORS; i++) { + if (isNotBlank(getProperty(REST_URL, i))) { + return true; + } + } for (int i = 0; i <= MAX_NUM_CLIENTS; i++) { if (isNotBlank(getProperty(FORMCLIENT_LOGIN_URL, i)) && isNotBlank(getProperty(FORMCLIENT_AUTHENTICATOR, i))) { return true; @@ -212,6 +221,9 @@ protected boolean hasHttpClients() { if (isNotBlank(getProperty(INDIRECTBASICAUTH_AUTHENTICATOR, i))) { return true; } + if (isNotBlank(getProperty(DIRECTBASICAUTH_AUTHENTICATOR, i))) { + return true; + } } return false; } diff --git a/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConstants.java b/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConstants.java index 66c84a5578..b5d7fd7e43 100644 --- a/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConstants.java +++ b/pac4j-config/src/main/java/org/pac4j/config/client/PropertiesConstants.java @@ -87,6 +87,8 @@ public interface PropertiesConstants { String ANONYMOUS = "anonymous"; + String DIRECTBASICAUTH_AUTHENTICATOR = "directBasicAuth.authenticator"; + String LDAP_TYPE = "ldap.type"; String LDAP_DN_FORMAT = "ldap.dnFormat"; String LDAP_ATTRIBUTES = "ldap.principalAttributes"; @@ -158,6 +160,8 @@ public interface PropertiesConstants { String DB_DATASOURCE_JNDI = "db.dataSourceJndi"; String DB_PASSWORD_ENCODER = "db.passwordEncoder"; + String REST_URL = "rest.url"; + String SPRING_ENCODER = "encoder.spring"; String SPRING_ENCODER_TYPE = "encoder.spring.type"; enum SpringEncoderType {BCRYPT, NOOP, PBKDF2, SCRYPT, STANDARD} diff --git a/pac4j-config/src/test/java/org/pac4j/config/client/PropertiesConfigFactoryTests.java b/pac4j-config/src/test/java/org/pac4j/config/client/PropertiesConfigFactoryTests.java index 85865cb183..398ee48b6d 100644 --- a/pac4j-config/src/test/java/org/pac4j/config/client/PropertiesConfigFactoryTests.java +++ b/pac4j-config/src/test/java/org/pac4j/config/client/PropertiesConfigFactoryTests.java @@ -11,8 +11,10 @@ import org.pac4j.core.context.Pac4jConstants; import org.pac4j.core.credentials.UsernamePasswordCredentials; import org.pac4j.core.util.TestsConstants; +import org.pac4j.http.client.direct.DirectBasicAuthClient; import org.pac4j.http.client.indirect.FormClient; import org.pac4j.http.client.indirect.IndirectBasicAuthClient; +import org.pac4j.http.credentials.authenticator.RestAuthenticator; import org.pac4j.http.credentials.authenticator.test.SimpleTestUsernamePasswordAuthenticator; import org.pac4j.ldap.profile.service.LdapProfileService; import org.pac4j.ldap.test.tools.LdapServer; @@ -102,6 +104,9 @@ public void test() throws Exception { properties.put(INDIRECTBASICAUTH_AUTHENTICATOR.concat(".5"), "db"); + properties.put(REST_URL.concat(".3"), PAC4J_BASE_URL); + properties.put(DIRECTBASICAUTH_AUTHENTICATOR.concat(".7"), "rest.3"); + LdapServer ldapServer = null; try { ldapServer = new LdapServer(); @@ -111,7 +116,7 @@ public void test() throws Exception { final PropertiesConfigFactory factory = new PropertiesConfigFactory(CALLBACK_URL, properties); final Config config = factory.build(); final Clients clients = config.getClients(); - assertEquals(12, clients.getClients().size()); + assertEquals(13, clients.getClients().size()); final FacebookClient fbClient = (FacebookClient) clients.findClient("FacebookClient"); assertEquals(ID, fbClient.getKey()); @@ -169,6 +174,11 @@ public void test() throws Exception { dbAuthenticator.validate(dbCredentials, MockWebContext.create()); assertNotNull(dbCredentials.getUserProfile()); + final DirectBasicAuthClient directBasicAuthClient = (DirectBasicAuthClient) clients.findClient("DirectBasicAuthClient.7"); + assertNotNull(directBasicAuthClient); + final RestAuthenticator restAuthenticator = (RestAuthenticator) directBasicAuthClient.getAuthenticator(); + assertEquals(PAC4J_BASE_URL, restAuthenticator.getUrl()); + } finally { if (ldapServer != null) { ldapServer.stop(); diff --git a/pac4j-core/src/main/java/org/pac4j/core/util/CommonHelper.java b/pac4j-core/src/main/java/org/pac4j/core/util/CommonHelper.java index cf1c992d02..eafffb28ac 100644 --- a/pac4j-core/src/main/java/org/pac4j/core/util/CommonHelper.java +++ b/pac4j-core/src/main/java/org/pac4j/core/util/CommonHelper.java @@ -212,37 +212,6 @@ public static String toString(final Class clazz, final Object... args) { return sb.toString(); } - /** - * Extract the prefix of the name. - * - * @param name the name - * @return the prefix - */ - protected static String extractPrefix(final String name) { - String prefix = null; - if (name != null) { - int prefixEnd = name.indexOf(":"); - if (prefixEnd != -1) { - prefix = name.substring(0, prefixEnd); - } - } - return prefix; - } - - /** - * Add a slash at the beginning of a path if missing. - * - * @param path the path - * @return the completed path - */ - protected static String startWithSlash(final String path) { - if (!path.startsWith("/")) { - return "/" + path; - } else { - return path; - } - } - /** * Return a random string of a certain size. * diff --git a/pac4j-cas/src/main/java/org/pac4j/cas/util/HttpUtils.java b/pac4j-core/src/main/java/org/pac4j/core/util/HttpUtils.java similarity index 58% rename from pac4j-cas/src/main/java/org/pac4j/cas/util/HttpUtils.java rename to pac4j-core/src/main/java/org/pac4j/core/util/HttpUtils.java index d4c08f8886..7580d50035 100644 --- a/pac4j-cas/src/main/java/org/pac4j/cas/util/HttpUtils.java +++ b/pac4j-core/src/main/java/org/pac4j/core/util/HttpUtils.java @@ -1,17 +1,17 @@ -package org.pac4j.cas.util; +package org.pac4j.core.util; import org.pac4j.core.context.HttpConstants; -import org.pac4j.core.util.CommonHelper; +import java.io.BufferedReader; import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; +import java.util.Map; /** - * This is {@link HttpUtils} that provides utility functions - * to deal with opening connections, building error messages - * and closing connections, etc. + * This class provides utility functions to deal with opening connections, + * building error messages and closing connections, etc. * * @author Misagh Moayyed * @since 1.8.0 @@ -35,24 +35,44 @@ public static String buildHttpErrorMessage(final HttpURLConnection connection) t } public static HttpURLConnection openPostConnection(final URL url) throws IOException { - return openConnection(url, "POST"); + return openConnection(url, HttpConstants.HTTP_METHOD.POST.name(), null); + } + + public static HttpURLConnection openPostConnection(final URL url, final Map headers) throws IOException { + return openConnection(url, HttpConstants.HTTP_METHOD.POST.name(), headers); } public static HttpURLConnection openDeleteConnection(final URL url) throws IOException { - return openConnection(url, "DELETE"); + return openConnection(url, HttpConstants.HTTP_METHOD.DELETE.name(), null); } - public static HttpURLConnection openConnection(final URL url, final String requestMethod) throws IOException { + protected static HttpURLConnection openConnection(final URL url, final String requestMethod, final Map headers) throws IOException { final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.setDoOutput(true); connection.setRequestMethod(requestMethod); connection.setConnectTimeout(connectTimeout); connection.setReadTimeout(readTimeout); + if (headers != null) { + for (final Map.Entry entry : headers.entrySet()) { + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } return connection; } - public static String encodeQueryParam(final String paramName, final String paramValue) throws UnsupportedEncodingException { + public static String readBody(final HttpURLConnection connection) throws IOException { + try (final InputStreamReader isr = new InputStreamReader(connection.getInputStream(), "UTF-8"); final BufferedReader br = new BufferedReader(isr)) { + final StringBuilder sb = new StringBuilder(); + String output; + while ((output = br.readLine()) != null) { + sb.append(output); + } + return sb.toString(); + } + } + + public static String encodeQueryParam(final String paramName, final String paramValue) { return CommonHelper.urlEncode(paramName) + "=" + CommonHelper.urlEncode(paramValue); } diff --git a/pac4j-couch/pom.xml b/pac4j-couch/pom.xml index 54babd6650..dc5bc25ee0 100644 --- a/pac4j-couch/pom.xml +++ b/pac4j-couch/pom.xml @@ -1,76 +1,81 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-couch - jar - pac4j for CouchDB + pac4j-couch + jar + pac4j for CouchDB - - 1.4.4 - + + 1.4.4 + - - - org.pac4j - pac4j-core - - - org.ektorp - org.ektorp - ${ektorp.version} - - - - org.pac4j - pac4j-core - test-jar - test - - - io.bdrc - mcouch-ektorp - 1.0.0 - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - org.apache.shiro - shiro-core - test - - - + + + org.pac4j + pac4j-core + + + org.ektorp + org.ektorp + ${ektorp.version} + + + com.fasterxml.jackson.core + jackson-databind + 2.3.3 + + + + org.pac4j + pac4j-core + test-jar + test + + + io.bdrc + mcouch-ektorp + 1.0.0 + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + org.apache.shiro + shiro-core + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.couch - org.pac4j.couch.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.couch + org.pac4j.couch.*;version=${project.version} + * + + + + + diff --git a/pac4j-gae/pom.xml b/pac4j-gae/pom.xml index 444b2a5f29..cc8fcf7ea3 100644 --- a/pac4j-gae/pom.xml +++ b/pac4j-gae/pom.xml @@ -1,28 +1,28 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-gae - jar - pac4j for GAE UserService mechanism + pac4j-gae + jar + pac4j for GAE UserService mechanism - 1.9.50 - 1.1 + 1.9.50 + 1.1 - - - org.pac4j - pac4j-core - - + + + org.pac4j + pac4j-core + + com.google.appengine appengine-api-1.0-sdk ${gae.version} @@ -37,29 +37,29 @@ jsr107cache ${jsr107cache.version} - - javax.servlet - javax.servlet-api - provided - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - + + javax.servlet + javax.servlet-api + provided + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + com.google.appengine appengine-testing ${gae.version} @@ -77,23 +77,23 @@ ${gae.version} test - - + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.gae - org.pac4j.gae.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.gae + org.pac4j.gae.*;version=${project.version} + * + + + + + diff --git a/pac4j-http/pom.xml b/pac4j-http/pom.xml index a306a7545b..5e34412396 100644 --- a/pac4j-http/pom.xml +++ b/pac4j-http/pom.xml @@ -1,71 +1,123 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-http - jar - pac4j for HTTP protocol + pac4j-http + jar + pac4j for HTTP protocol - - - org.pac4j - pac4j-core - - - commons-codec - commons-codec - true - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - org.mockito - mockito-core - test - - - com.google.guava - guava - test - - - + + 2.3.1 + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.http - org.pac4j.http.*;version=${project.version} - * - - - - - + + + org.pac4j + pac4j-core + + + commons-codec + commons-codec + true + + + com.fasterxml.jackson.core + jackson-databind + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + org.mockito + mockito-core + test + + + com.google.guava + guava + test + + + org.nanohttpd + nanohttpd + ${nanohttpd.version} + test + + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.http + org.pac4j.http.*;version=${project.version} + * + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + jar + test-jar + + + + + + diff --git a/pac4j-http/src/main/java/org/pac4j/http/credentials/authenticator/RestAuthenticator.java b/pac4j-http/src/main/java/org/pac4j/http/credentials/authenticator/RestAuthenticator.java new file mode 100644 index 0000000000..a501e91496 --- /dev/null +++ b/pac4j-http/src/main/java/org/pac4j/http/credentials/authenticator/RestAuthenticator.java @@ -0,0 +1,153 @@ +package org.pac4j.http.credentials.authenticator; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.pac4j.core.context.HttpConstants; +import org.pac4j.core.context.WebContext; +import org.pac4j.core.credentials.UsernamePasswordCredentials; +import org.pac4j.core.credentials.authenticator.Authenticator; +import org.pac4j.core.exception.CredentialsException; +import org.pac4j.core.exception.HttpAction; +import org.pac4j.core.exception.TechnicalException; +import org.pac4j.core.profile.definition.CommonProfileDefinition; +import org.pac4j.core.profile.definition.ProfileDefinitionAware; +import org.pac4j.core.util.CommonHelper; +import org.pac4j.core.util.HttpUtils; +import org.pac4j.http.profile.RestProfile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * Authenticates against a REST API. The username/password are passed as a basic auth via a POST request, + * the JSON response is a user profile. + * + * @author Jerome Leleu + * @since 2.1.0 + */ +public class RestAuthenticator extends ProfileDefinitionAware implements Authenticator { + + private static final Logger logger = LoggerFactory.getLogger(RestAuthenticator.class); + + private ObjectMapper mapper; + + private String url; + + public RestAuthenticator() {} + + public RestAuthenticator(final String url) { + this.url = url; + } + + @Override + protected void internalInit(final WebContext context) { + CommonHelper.assertNotBlank("url", url); + defaultProfileDefinition(new CommonProfileDefinition<>(x -> new RestProfile())); + if (mapper == null) { + mapper = new ObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); + mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + } + } + + @Override + public void validate(final UsernamePasswordCredentials credentials, final WebContext context) throws HttpAction, CredentialsException { + init(context); + + final String username = credentials.getUsername(); + final String password = credentials.getPassword(); + if (CommonHelper.isBlank(username) || CommonHelper.isBlank(password)) { + logger.info("Empty username or password"); + return; + } + + final String body = callRestApi(username, password); + logger.debug("body: {}", body); + if (body != null) { + buildProfile(credentials, body); + } + } + + protected void buildProfile(final UsernamePasswordCredentials credentials, final String body) throws HttpAction, CredentialsException { + final RestProfile profileClass = getProfileDefinition().newProfile(); + final RestProfile profile; + try { + profile = mapper.readValue(body, profileClass.getClass()); + } catch (final IOException e) { + throw new TechnicalException(e); + } + logger.debug("profile: {}", profile); + credentials.setUserProfile(profile); + } + + /** + * Return the body from the REST API, passing the username/pasword auth. + * To be overridden using another HTTP client if necessary. + * + * @param username the username + * @param password the password + * @return the response body + * @throws HttpAction whether an extra HTTP action is required + * @throws CredentialsException whether an authentication error occurs + */ + protected String callRestApi(final String username, final String password) throws HttpAction, CredentialsException { + + final String basicAuth; + try { + basicAuth = Base64.getEncoder().encodeToString((username + ":" + password).getBytes("UTF-8")); + } catch (final UnsupportedEncodingException e) { + throw new TechnicalException(e); + } + + final Map headers = new HashMap<>(); + headers.put(HttpConstants.AUTHORIZATION_HEADER, HttpConstants.BASIC_HEADER_PREFIX + basicAuth); + + HttpURLConnection connection = null; + try { + connection = HttpUtils.openPostConnection(new URL(url), headers); + int code = connection.getResponseCode(); + if (code == 200) { + logger.debug("Authentication success for username: {}", username); + return HttpUtils.readBody(connection); + } else if (code == 401 || code == 403) { + logger.info("Authentication failure for username: {} -> {}", username, HttpUtils.buildHttpErrorMessage(connection)); + return null; + } else { + logger.warn("Unexpected error for username: {} -> {}", username, HttpUtils.buildHttpErrorMessage(connection)); + return null; + } + } catch (final IOException e) { + throw new TechnicalException(e); + } finally { + HttpUtils.closeConnection(connection); + } + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } + + public ObjectMapper getMapper() { + return mapper; + } + + public void setMapper(final ObjectMapper mapper) { + this.mapper = mapper; + } + + @Override + public String toString() { + return CommonHelper.toString(this.getClass(), "url", url, "mapper", mapper); + } +} diff --git a/pac4j-http/src/main/java/org/pac4j/http/profile/RestProfile.java b/pac4j-http/src/main/java/org/pac4j/http/profile/RestProfile.java new file mode 100644 index 0000000000..88a04d4068 --- /dev/null +++ b/pac4j-http/src/main/java/org/pac4j/http/profile/RestProfile.java @@ -0,0 +1,12 @@ +package org.pac4j.http.profile; + +import org.pac4j.core.profile.CommonProfile; + +/** + * REST profile. + * + * @author Jerome Leleu + * @since 2.1.0 + */ +public class RestProfile extends CommonProfile { +} diff --git a/pac4j-http/src/test/java/org/pac4j/http/credentials/authenticator/RestAuthenticatorIT.java b/pac4j-http/src/test/java/org/pac4j/http/credentials/authenticator/RestAuthenticatorIT.java new file mode 100644 index 0000000000..4fb649a5c3 --- /dev/null +++ b/pac4j-http/src/test/java/org/pac4j/http/credentials/authenticator/RestAuthenticatorIT.java @@ -0,0 +1,65 @@ +package org.pac4j.http.credentials.authenticator; + +import fi.iki.elonen.NanoHTTPD; +import org.junit.BeforeClass; +import org.junit.Test; +import org.pac4j.core.context.MockWebContext; +import org.pac4j.core.credentials.UsernamePasswordCredentials; +import org.pac4j.core.exception.CredentialsException; +import org.pac4j.core.exception.HttpAction; +import org.pac4j.core.exception.TechnicalException; +import org.pac4j.core.util.TestsConstants; +import org.pac4j.core.util.TestsHelper; +import org.pac4j.http.profile.RestProfile; +import org.pac4j.http.test.tools.ServerResponse; +import org.pac4j.http.test.tools.WebServer; + +import static org.junit.Assert.*; + +/** + * Tests {@link RestAuthenticator}. + * + * @author Jerome Leleu + * @since 2.1.0 + */ +public final class RestAuthenticatorIT implements TestsConstants { + + private static final int PORT = 8088; + + @BeforeClass + public static void setUp() { + final WebServer webServer = new WebServer(PORT) + .defineResponse("ok", new ServerResponse(NanoHTTPD.Response.Status.OK, "application/json", "{ 'id': '" + ID + "', roles: [\"" + ROLE + "\"] }")) + .defineResponse("notfound", new ServerResponse(NanoHTTPD.Response.Status.NOT_FOUND, "plain/text", "Not found")) + .defineResponse("pe", new ServerResponse(NanoHTTPD.Response.Status.OK, "plain/text", "bad")); + webServer.start(); + } + + @Test + public void testProfileOk() throws HttpAction, CredentialsException { + final RestAuthenticator authenticator = new RestAuthenticator("http://localhost:" + PORT + "?r=ok"); + final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(GOOD_USERNAME, PASSWORD, CLIENT_NAME); + authenticator.validate(credentials, MockWebContext.create()); + final RestProfile profile = (RestProfile) credentials.getUserProfile(); + assertNotNull(profile); + assertEquals(ID, profile.getId()); + assertEquals(1, profile.getRoles().size()); + assertEquals(ROLE, profile.getRoles().iterator().next()); + } + + @Test + public void testNotFound() throws HttpAction, CredentialsException { + final RestAuthenticator authenticator = new RestAuthenticator("http://localhost:" + PORT + "?r=notfound"); + final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(GOOD_USERNAME, PASSWORD, CLIENT_NAME); + authenticator.validate(credentials, MockWebContext.create()); + final RestProfile profile = (RestProfile) credentials.getUserProfile(); + assertNull(profile); + } + + @Test + public void testParsingError() throws HttpAction, CredentialsException { + final RestAuthenticator authenticator = new RestAuthenticator("http://localhost:" + PORT + "?r=pe"); + final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(GOOD_USERNAME, PASSWORD, CLIENT_NAME); + TestsHelper.expectException(() -> authenticator.validate(credentials, MockWebContext.create()), TechnicalException.class, "com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'bad': was expecting ('true', 'false' or 'null')\n at [Source: bad; line: 1, column: 7]"); + } +} diff --git a/pac4j-http/src/test/java/org/pac4j/http/test/tools/ServerResponse.java b/pac4j-http/src/test/java/org/pac4j/http/test/tools/ServerResponse.java new file mode 100644 index 0000000000..42b5903891 --- /dev/null +++ b/pac4j-http/src/test/java/org/pac4j/http/test/tools/ServerResponse.java @@ -0,0 +1,36 @@ +package org.pac4j.http.test.tools; + +import fi.iki.elonen.NanoHTTPD; + +/** + * A server response. + * + * @author Jerome Leleu + * @since 2.1.0 + */ +public class ServerResponse { + + private final NanoHTTPD.Response.IStatus status; + + private final String mimeType; + + private final String body; + + public ServerResponse(final NanoHTTPD.Response.IStatus status, final String mimeType, final String body) { + this.status = status; + this.mimeType = mimeType; + this.body = body; + } + + public NanoHTTPD.Response.IStatus getStatus() { + return status; + } + + public String getMimeType() { + return mimeType; + } + + public String getBody() { + return body; + } +} diff --git a/pac4j-http/src/test/java/org/pac4j/http/test/tools/WebServer.java b/pac4j-http/src/test/java/org/pac4j/http/test/tools/WebServer.java new file mode 100644 index 0000000000..6f3153f9fe --- /dev/null +++ b/pac4j-http/src/test/java/org/pac4j/http/test/tools/WebServer.java @@ -0,0 +1,52 @@ +package org.pac4j.http.test.tools; + +import fi.iki.elonen.NanoHTTPD; +import org.pac4j.core.exception.TechnicalException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A web server for tests. + * + * @author Jerome Leleu + * @since 2.1.0 + */ +public class WebServer extends NanoHTTPD { + + private Map responses = new HashMap<>(); + + public WebServer(final int port) { + super(port); + } + + public WebServer defineResponse(final String key, final ServerResponse response) { + responses.put(key, response); + return this; + } + + public void start() { + try { + start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); + } catch (final IOException e) { + throw new TechnicalException(e); + } + } + + @Override + public Response serve(IHTTPSession session) { + String r = null; + final List parameterList = session.getParameters().get("r"); + if (parameterList != null && parameterList.size() > 0) { + r = parameterList.get(0); + } + final ServerResponse response = responses.get(r); + if (response != null) { + return newFixedLengthResponse(response.getStatus(), response.getMimeType(), response.getBody()); + } else { + return newFixedLengthResponse(NanoHTTPD.Response.Status.SERVICE_UNAVAILABLE, "plain/text", "no response available"); + } + } +} diff --git a/pac4j-jwt/pom.xml b/pac4j-jwt/pom.xml index 7659d4fbdd..55cd7cc34c 100644 --- a/pac4j-jwt/pom.xml +++ b/pac4j-jwt/pom.xml @@ -1,74 +1,74 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-jwt - jar - pac4j for JWT + pac4j-jwt + jar + pac4j for JWT - - 1.56 - + + 1.56 + - - - org.pac4j - pac4j-core - - - com.nimbusds - nimbus-jose-jwt - - - org.bouncycastle - bcprov-jdk15on - ${bcprov.version} - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - org.pac4j - pac4j-oauth - test - - - + + + org.pac4j + pac4j-core + + + com.nimbusds + nimbus-jose-jwt + + + org.bouncycastle + bcprov-jdk15on + ${bcprov.version} + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + org.pac4j + pac4j-oauth + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.jwt - org.pac4j.jwt.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.jwt + org.pac4j.jwt.*;version=${project.version} + * + + + + + diff --git a/pac4j-kerberos/pom.xml b/pac4j-kerberos/pom.xml index 5b5b1acf81..cbef7a29f6 100644 --- a/pac4j-kerberos/pom.xml +++ b/pac4j-kerberos/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/pac4j-ldap/pom.xml b/pac4j-ldap/pom.xml index 4ff78ab314..f1dedb8d01 100644 --- a/pac4j-ldap/pom.xml +++ b/pac4j-ldap/pom.xml @@ -1,69 +1,69 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-ldap - jar - pac4j for LDAP + pac4j-ldap + jar + pac4j for LDAP - - 1.2.1 - + + 1.2.1 + - - - org.pac4j - pac4j-core - - - org.ldaptive - ldaptive - ${ldaptive.version} - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - com.unboundid - unboundid-ldapsdk - test - - - + + + org.pac4j + pac4j-core + + + org.ldaptive + ldaptive + ${ldaptive.version} + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + com.unboundid + unboundid-ldapsdk + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.ldap - org.pac4j.ldap.*;version=${project.version} - * - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.ldap + org.pac4j.ldap.*;version=${project.version} + * + + + org.apache.maven.plugins maven-source-plugin @@ -102,7 +102,7 @@ - - + + diff --git a/pac4j-mongo/pom.xml b/pac4j-mongo/pom.xml index 1d0f0593d9..bf095898cf 100644 --- a/pac4j-mongo/pom.xml +++ b/pac4j-mongo/pom.xml @@ -1,77 +1,115 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-mongo - jar - pac4j for MongoDB + pac4j-mongo + jar + pac4j for MongoDB - - 3.4.2 - 2.0.0 - + + 3.4.2 + 2.0.0 + - - - org.pac4j - pac4j-core - - - org.mongodb - mongo-java-driver - ${mongo-driver.version} - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - org.apache.shiro - shiro-core - test - - - de.flapdoodle.embed - de.flapdoodle.embed.mongo - ${flapdoodle.version} - test - - - + + + org.pac4j + pac4j-core + + + org.mongodb + mongo-java-driver + ${mongo-driver.version} + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + org.apache.shiro + shiro-core + test + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + ${flapdoodle.version} + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.mongo - org.pac4j.mongo.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.mongo + org.pac4j.mongo.*;version=${project.version} + * + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + jar + test-jar + + + + + + diff --git a/pac4j-oauth/pom.xml b/pac4j-oauth/pom.xml index 2360c5c3f3..e7c5e97206 100644 --- a/pac4j-oauth/pom.xml +++ b/pac4j-oauth/pom.xml @@ -1,80 +1,78 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-oauth - jar - pac4j for OAuth protocol + pac4j-oauth + jar + pac4j for OAuth protocol - - 3.3.0 - 2.8.7 - + + 3.3.0 + - - - org.pac4j - pac4j-core - - - commons-codec - commons-codec - - - com.github.scribejava - scribejava-apis - ${scribe.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - javax.servlet - javax.servlet-api - provided - - + + + org.pac4j + pac4j-core + + + commons-codec + commons-codec + + + com.github.scribejava + scribejava-apis + ${scribe.version} + + + com.fasterxml.jackson.core + jackson-databind + + + javax.servlet + javax.servlet-api + provided + + org.pac4j pac4j-core test-jar test - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.oauth - org.pac4j.oauth.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.oauth + org.pac4j.oauth.*;version=${project.version} + * + + + + + diff --git a/pac4j-oauth/src/main/java/org/pac4j/oauth/config/OAuthConfiguration.java b/pac4j-oauth/src/main/java/org/pac4j/oauth/config/OAuthConfiguration.java index 78e19607ca..a0bb607581 100644 --- a/pac4j-oauth/src/main/java/org/pac4j/oauth/config/OAuthConfiguration.java +++ b/pac4j-oauth/src/main/java/org/pac4j/oauth/config/OAuthConfiguration.java @@ -6,9 +6,9 @@ import com.github.scribejava.core.model.Token; import com.github.scribejava.core.oauth.OAuthService; import org.pac4j.core.client.IndirectClient; -import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.WebContext; import org.pac4j.core.util.CommonHelper; +import org.pac4j.core.util.HttpUtils; import org.pac4j.core.util.InitializableWebObject; import org.pac4j.oauth.profile.definition.OAuthProfileDefinition; @@ -34,10 +34,6 @@ public class OAuthConfiguration - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-oidc - jar - pac4j for OpenID Connect protocol + pac4j-oidc + jar + pac4j for OpenID Connect protocol - - 5.24.2 - + + 5.24.2 + - - - org.pac4j - pac4j-core - - - com.nimbusds - oauth2-oidc-sdk - ${oauth-oidc-sdk.version} - - - com.nimbusds - nimbus-jose-jwt - - - - - com.nimbusds - nimbus-jose-jwt - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - + + + org.pac4j + pac4j-core + + + com.nimbusds + oauth2-oidc-sdk + ${oauth-oidc-sdk.version} + + + com.nimbusds + nimbus-jose-jwt + + + + + com.nimbusds + nimbus-jose-jwt + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.oidc - org.pac4j.oidc.*;version=${project.version} - * - - - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.oidc + org.pac4j.oidc.*;version=${project.version} + * + + + + + diff --git a/pac4j-oidc/src/main/java/org/pac4j/oidc/config/OidcConfiguration.java b/pac4j-oidc/src/main/java/org/pac4j/oidc/config/OidcConfiguration.java index bb0c248ea0..bb3b44a8b3 100644 --- a/pac4j-oidc/src/main/java/org/pac4j/oidc/config/OidcConfiguration.java +++ b/pac4j-oidc/src/main/java/org/pac4j/oidc/config/OidcConfiguration.java @@ -6,10 +6,10 @@ import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.auth.*; import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata; -import org.pac4j.core.context.HttpConstants; import org.pac4j.core.context.WebContext; import org.pac4j.core.exception.TechnicalException; import org.pac4j.core.util.CommonHelper; +import org.pac4j.core.util.HttpUtils; import org.pac4j.core.util.InitializableWebObject; import java.io.IOException; @@ -69,10 +69,6 @@ public class OidcConfiguration extends InitializableWebObject { /* max clock skew in seconds */ private int maxClockSkew = DEFAULT_MAX_CLOCK_SKEW; - /* timeouts for token and userinfo requests */ - private int connectTimeout = HttpConstants.DEFAULT_CONNECT_TIMEOUT; - private int readTimeout = HttpConstants.DEFAULT_READ_TIMEOUT; - private ResourceRetriever resourceRetriever; private OIDCProviderMetadata providerMetadata; @@ -205,20 +201,24 @@ public void setMaxClockSkew(final int maxClockSkew) { this.maxClockSkew = maxClockSkew; } + @Deprecated public int getConnectTimeout() { - return connectTimeout; + return HttpUtils.getConnectTimeout(); } + @Deprecated public void setConnectTimeout(final int connectTimeout) { - this.connectTimeout = connectTimeout; + HttpUtils.setConnectTimeout(connectTimeout); } + @Deprecated public int getReadTimeout() { - return readTimeout; + return HttpUtils.getReadTimeout(); } + @Deprecated public void setReadTimeout(final int readTimeout) { - this.readTimeout = readTimeout; + HttpUtils.setReadTimeout(readTimeout); } public ResourceRetriever getResourceRetriever() { @@ -278,7 +278,7 @@ public void setLogoutUrl(final String logoutUrl) { public String toString() { return CommonHelper.toString(this.getClass(), "clientId", clientId, "secret", "[protected]", "discoveryURI", discoveryURI, "scope", scope, "customParams", customParams, "clientAuthenticationMethod", clientAuthenticationMethod, "useNonce", useNonce, "preferredJwsAlgorithm", preferredJwsAlgorithm, - "maxClockSkew", maxClockSkew, "connectTimeout", connectTimeout, "readTimeout", readTimeout, "resourceRetriever", resourceRetriever, + "maxClockSkew", maxClockSkew, "connectTimeout", HttpUtils.getConnectTimeout(), "readTimeout", HttpUtils.getReadTimeout(), "resourceRetriever", resourceRetriever, "callbackUrl", callbackUrl, "responseType", responseType, "responseMode", responseMode, "logoutUrl", logoutUrl); } } diff --git a/pac4j-openid/pom.xml b/pac4j-openid/pom.xml index 4cb8dcb9df..5262112d87 100644 --- a/pac4j-openid/pom.xml +++ b/pac4j-openid/pom.xml @@ -37,11 +37,11 @@ org.slf4j jcl-over-slf4j - - xml-apis - xml-apis + + xml-apis + xml-apis ${xml-apis.version} - + javax.servlet javax.servlet-api diff --git a/pac4j-sql/pom.xml b/pac4j-sql/pom.xml index 3364e0ef6b..19b2e9a155 100644 --- a/pac4j-sql/pom.xml +++ b/pac4j-sql/pom.xml @@ -1,70 +1,70 @@ - 4.0.0 + 4.0.0 - - org.pac4j - pac4j - 2.1.0-SNAPSHOT - + + org.pac4j + pac4j + 2.1.0-SNAPSHOT + - pac4j-sql - jar - pac4j for relational DB + pac4j-sql + jar + pac4j for relational DB - - 2.78 - + + 2.78 + - - - org.pac4j - pac4j-core - - - org.jdbi - jdbi - ${jdbi.version} - - - - org.pac4j - pac4j-core - test-jar - test - - - junit - junit - test - - - org.springframework.security - spring-security-crypto - test - - - com.h2database - h2 - ${h2.version} - test - - - + + + org.pac4j + pac4j-core + + + org.jdbi + jdbi + ${jdbi.version} + + + + org.pac4j + pac4j-core + test-jar + test + + + junit + junit + test + + + org.springframework.security + spring-security-crypto + test + + + com.h2database + h2 + ${h2.version} + test + + + - - - - org.apache.felix - maven-bundle-plugin - - - org.pac4j.sql - org.pac4j.sql.*;version=${project.version} - * - - - + + + + org.apache.felix + maven-bundle-plugin + + + org.pac4j.sql + org.pac4j.sql.*;version=${project.version} + * + + + org.apache.maven.plugins maven-source-plugin @@ -103,7 +103,7 @@ - - + + diff --git a/pom.xml b/pom.xml index fcb799de75..5e96c594b3 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,7 @@ 3.2.1 1.4.194 1.8 + 2.8.7 UTF-8 UTF-8 @@ -152,6 +153,11 @@ nimbus-jose-jwt ${nimbus-jose-jwt.version} + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + org.pac4j