Git Product home page Git Product logo

buji-pac4j's Introduction

The buji-pac4j project is an easy and powerful security library for Shiro web applications which supports authentication and authorization, but also advanced features like CSRF protection. It's based on Java 8, Shiro 1.3 and on the pac4j security engine. It's available under the Apache 2 license.

Main concepts and components:

  1. A client 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:

▸ OAuth - SAML - CAS - OpenID Connect - HTTP - OpenID - Google App Engine - LDAP - SQL - JWT - MongoDB - Stormpath - IP address

  1. An authorizer is meant to check authorizations on the authenticated user profile(s) or on the current web context:

▸ Roles / permissions - Anonymous / remember-me / (fully) authenticated - Profile type, attribute - CORS - CSRF - Security headers - IP address, HTTP method

  1. The SecurityFilter 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

  2. The CallbackFilter finishes the login process for an indirect client.

==

Just follow these easy steps to secure your Shiro web application:

1) Add the required dependencies (buji-pac4j + pac4j-* libraries)

You need to add a dependency on:

  • the buji-pac4j library (groupId: io.buji, version: 2.0.2)
  • the appropriate pac4j submodules (groupId: org.pac4j, version: 1.9.2): pac4j-oauth for OAuth support (Facebook, Twitter...), pac4j-cas for CAS support, pac4j-ldap for LDAP authentication, etc.

All released artifacts are available in the Maven central repository.


2) Define the configuration (Config + Client + Authorizer)

The configuration (org.pac4j.core.config.Config) contains all the clients and authorizers required by the application to handle security.

It must be defined in your shiro.ini file:

[main]
roleAdminAuthGenerator = org.pac4j.demo.shiro.RoleAdminAuthGenerator

googleOidClient = org.pac4j.oidc.client.GoogleOidcClient
googleOidClient.clientID = googleClientID
googleOidClient.secret = googleSecret
googleOidClient.useNonce = true
googleOidClient.authorizationGenerator = $roleAdminAuthGenerator

saml2Config = org.pac4j.saml.client.SAML2ClientConfiguration
saml2Config.keystorePath = resource:samlKeystore.jks
saml2Config.keystorePassword = pac4j-demo-passwd
saml2Config.privateKeyPassword = pac4j-demo-passwd
saml2Config.identityProviderMetadataPath = resource:metadata-okta.xml
saml2Config.maximumAuthenticationLifetime = 3600
saml2Config.serviceProviderEntityId = http://localhost:8080/callback?client_name=SAML2Client
saml2Config.serviceProviderMetadataPath = sp-metadata.xml

saml2Client = org.pac4j.saml.client.SAML2Client
saml2Client.configuration = $saml2Config

facebookClient = org.pac4j.oauth.client.FacebookClient
facebookClient.key = fbkey
facebookClient.secret = fbSecret

twitterClient = org.pac4j.oauth.client.TwitterClient
twitterClient.key = twKey
twitterClient.secret = twSecret

simpleAuthenticator = org.pac4j.http.credentials.authenticator.test.SimpleTestUsernamePasswordAuthenticator

formClient = org.pac4j.http.client.indirect.FormClient
formClient.loginUrl = http://localhost:8080/loginForm.jsp
formClient.authenticator = $simpleAuthenticator

indirectBasicAuthClient = org.pac4j.http.client.indirect.IndirectBasicAuthClient
indirectBasicAuthClient.authenticator = $simpleAuthenticator

casClient = org.pac4j.cas.client.CasClient
casClient.casLoginUrl = https://casserverpac4j.herokuapp.com

jwtAuthenticator = org.pac4j.jwt.credentials.authenticator.JwtAuthenticator
jwtAuthenticator.signingSecret = signingSecret
jwtAuthenticator.encryptionSecret = encryptionSecret

parameterClient = org.pac4j.http.client.direct.ParameterClient
parameterClient.parameterName = token
parameterClient.authenticator = $jwtAuthenticator

directBasicAuthClient = org.pac4j.http.client.direct.DirectBasicAuthClient
directBasicAuthClient.authenticator = $simpleAuthenticator

clients = org.pac4j.core.client.Clients
clients.callbackUrl = http://localhost:8080/callback
clients.clients = $googleOidClient,$facebookClient,$twitterClient,$formClient,$indirectBasicAuthClient,$casClient,$saml2Client,$parameterClient,$directBasicAuthClient

requireRoleAdmin = org.pac4j.core.authorization.authorizer.RequireAnyRoleAuthorizer
requireRoleAdmin.elements = ROLE_ADMIN

customAuthorizer = org.pac4j.demo.shiro.CustomAuthorizer

excludedPathMatcher = org.pac4j.core.matching.ExcludedPathMatcher
excludedPathMatcher.excludePath = ^/facebook/notprotected\.jsp$

config = org.pac4j.core.config.Config
config.clients = $clients
config.authorizers = admin:$requireRoleAdmin,custom:$customAuthorizer
config.matchers = excludedPath:$excludedPathMatcher

http://localhost:8080/callback is the url of the callback endpoint, which is only necessary for indirect clients.

Notice that you can define:

  1. a specific SessionStore using the sessionStore property (by default, it uses the ShiroSessionStore which relies on the Shiro session management mechanism)

  2. specific matchers via the matchers map.


3) Protect urls (SecurityFilter)

You can protect (authentication + authorizations) the urls of your Shiro application by using the SecurityFilter and declaring the filter on the appropriate url mapping. It has the following behaviour:

  1. If the HTTP request matches the matchers configuration (or no matchers are defined), the security is applied. Otherwise, the user is automatically granted access.

  2. First, if the user is not authenticated (no profile) and if some clients have been defined in the clients parameter, a login is tried for the direct clients.

  3. Then, if the user has a profile, authorizations are checked according to the authorizers configuration. If the authorizations are valid, the user is granted access. Otherwise, a 403 error page is displayed.

  4. Finally, if the user is still not authenticated (no profile), he is redirected to the appropriate identity provider if the first defined client is an indirect one in the clients configuration. Otherwise, a 401 error page is displayed.

The following parameters are available:

  1. config: the security configuration previously defined

  2. clients (optional): the list of client names (separated by commas) used for authentication:

  • in all cases, this filter requires the user to be authenticated. Thus, if the clients is blank or not defined, the user must have been previously authenticated
  • if the client_name request parameter is provided, only this client (if it exists in the clients) is selected.
  1. authorizers (optional): the list of authorizer names (separated by commas) used to check authorizations:
  • if the authorizers is blank or not defined, no authorization is checked
  • the following authorizers are available by default (without defining them in the configuration):
    • isFullyAuthenticated to check if the user is authenticated but not remembered, isRemembered for a remembered user, isAnonymous to ensure the user is not authenticated, isAuthenticated to ensure the user is authenticated (not necessary by default unless you use the AnonymousClient)
    • hsts to use the StrictTransportSecurityHeader authorizer, nosniff for XContentTypeOptionsHeader, noframe for XFrameOptionsHeader , xssprotection for XSSProtectionHeader , nocache for CacheControlHeader or securityHeaders for the five previous authorizers
    • csrfToken to use the CsrfTokenGeneratorAuthorizer with the DefaultCsrfTokenGenerator (it generates a CSRF token and saves it as the pac4jCsrfToken request attribute and in the pac4jCsrfToken cookie), csrfCheck to check that this previous token has been sent as the pac4jCsrfToken header or parameter in a POST request and csrf to use both previous authorizers.
  1. matchers (optional): the list of matcher names (separated by commas) that the request must satisfy to check authentication / authorizations

  2. multiProfile (optional): it indicates whether multiple authentications (and thus multiple profiles) must be kept at the same time (false by default).

In your shiro.ini file:

[main]
pac4jRealm = io.buji.pac4j.realm.Pac4jRealm

pac4jSubjectFactory = io.buji.pac4j.subject.Pac4jSubjectFactory
securityManager.subjectFactory = $pac4jSubjectFactory

facebookSecurityFilter = io.buji.pac4j.filter.SecurityFilter
facebookSecurityFilter.config = $config
facebookSecurityFilter.clients = FacebookClient

[url]
/facebook/** = facebookSecurityFilter

Notice that you need a specific Pac4jRealm and a specific Pac4jSubjectFactory required by pac4j.


4) Define the callback endpoint only for indirect clients (CallbackFilter)

For indirect clients (like Facebook), the user is redirected to an external identity provider for login and then back to the application. Thus, a callback endpoint is required in the application. It is managed by the CallbackFilter which has the following behaviour:

  1. the credentials are extracted from the current request to fetch the user profile (from the identity provider) which is then saved in the web session

  2. finally, the user is redirected back to the originally requested url (or to the defaultUrl).

The following parameters are available:

  1. config: the security configuration previously defined

  2. defaultUrl (optional): it's the default url after login if no url was originally requested (/ by default)

  3. multiProfile (optional): it indicates whether multiple authentications (and thus multiple profiles) must be kept at the same time (false by default).

In your shiro.ini file:

[main]
callbackFilter = io.buji.pac4j.filter.CallbackFilter
callbackFilter.config = $config

[url]
/callback = callbackFilter

5) Get the user profile

Like for any Shiro web application, you can get the authenticated user via the SecurityUtils.getSubject().getPrincipals(). If the user is authenticated or remembered, the appropriate principal: Pac4jPrincipal will be stored in the principals, on which you can get the main profile (getProfile method) or all profiles (getProfiles method) of the authenticated user:

final PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
if (principals != null) {
    final Pac4jPrincipal principal = principals.oneByType(Pac4jPrincipal.class);
    if (principal != null) {
        CommonProfile profile = principal.getProfile();
    }
}

The retrieved profile is at least a CommonProfile, from which you can retrieve the most common attributes that all profiles share. But you can also cast the user profile to the appropriate profile according to the provider used for authentication. For example, after a Facebook authentication:

FacebookProfile facebookProfile = (FacebookProfile) commonProfile;

6) Logout

Like for any Shiro webapp, use the default logout filter (in your shiro.ini file):

[url]
/logout = logout

Migration guide

From the deprecated shiro-cas module (CAS support)

Instead of using the shiro-cas module, you need to use the buji-pac4j library and the pac4j-cas module. Though, the way both implementation work is close.

The CasFilter is replaced by the CallbackFilter which has the same role (receiving callbacks from identity providers), but not only for CAS.

The CasRealm is replaced by the Pac4jRealm and the CasSubjectFactory by the Pac4jsubjectFactory.

Finally, you must use the SecurityFilter to secure an url, instead of the default Shiro filters (like roles).

1.4 - > 2.0

The buji-pac4j library strongly changes in version 2:

  • the core and servlet modules are merged back into one main module
  • the ClientRealm is replaced by the Pac4jRealm and the ClientToken by the Pac4jToken
  • the ClientUserFilter, ClientPermissionsAuthorizationFilter and ClientRolesAuthorizationFilter.java are removed, more generally replaced by the SecurityFilter which ensures the url security (as usually in the pac4j world)
  • the CallbackFilter replaces the ClientFilter to finish the login process for indirect clients (as usually in the pac4j world).

Demo

The demo webapp: buji-pac4j-demo is available for tests and implements many authentication mechanisms: Facebook, Twitter, form, basic auth, CAS, SAML, OpenID Connect, JWT...

Release notes

See the release notes. Learn more by browsing the buji-pac4j Javadoc and the pac4j Javadoc.

Need help?

If you have any question, please use the following mailing lists:

Development

The version 2.0.3-SNAPSHOT is under development.

Maven artifacts are built via Travis: Build Status and available in the Sonatype snapshots repository. This repository must be added in the Maven pom.xml file for example:

<repositories>
  <repository>
    <id>sonatype-nexus-snapshots</id>
    <name>Sonatype Nexus Snapshots</name>
    <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    <releases>
      <enabled>false</enabled>
    </releases>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

buji-pac4j's People

Contributors

leleuj avatar benmccann avatar miremond avatar qinfchen avatar vonzeppelin avatar orthographic-pedant avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.