Skip to main content
Version: 8.2411.x.x RR

Configuration - Ninja Authentication Filter

Functionality

The NinjaAuthenticationFilter is a Java ServletFilter that can enforce authentication or optional authentication, depending on its configuration. It provides the following functionality (for details see the chapter: Ninja Features):

  • Secure Token Verification: The filter validates incoming SecTokens to establish an identity.
  • SAML Assertion Verification: The filter can validate SAML Assertions to establish an identity in the same way as SecTokens.
  • Servlet Authentication: The filter establishes a container identity according to the Java Servlet Specification (by injecting a UserPrincipal into the request instance).
  • JAAS Authentication: The filter can, if configured, establish a JAAS authentication (using the Subject.doAs() method).
  • Container Session Invalidation: The filter can be configured to invalidate sessions upon receiving requests on a particular URL path. It can respond to that by redirecting or by dispatching to an internal resource.
  • Multiple Signer Certificates: The filter can verify token signature trust using multiple configured certificates.
  • Optional Authentication: The filter can be configured to forward requests with unauthenticated sessions to the application, even if no token is provided.
  • Development Mode: This filter supports DevMode (see the chapter: Development Mode)
  • Variable Token Source Header: The filter can extract tokens from arbitrary request headers and can decode BasicAuth transport in the same way as Ninja JAAS login modules. In addition, it can decode Bearer-type Authorization headers as defined by the OAuth Bearer Token standard.

Authentication Filter Configuration

The NinjaAuthenticationFilter supports all common configuration properties. In addition, the following options can be configured:

Sets the HTTP header in which the filter expects the authentication token. If this is set to ‘Authorization’, then a Basic Authentication scheme is assumed and decoded.

Syntax: <header>

Default: Authorization

Realm

If Header=Authorization is configured and the filter sends a WWW-Authenticate challenge, this setting defines the realm for which authentication is requested.

Syntax: <Realm>

Default: Nevis

AuthenticationOptional

Enables optional authentication that lets requests without tokens of unauthentic sessions pass. Used for scenarios where both authentic and anonymous access shall be allowed. Note that requests of unauthentic sessions with invalid tokens will always be blocked.

Syntax: true | false

Default: false

CachePrincipal

If set to true, the Principal will be stored in the session (i.e. it will be cached). If set to false, the SecToken will be checked on each request. Caching the Principal provides a potential performance optimization, but not caching the Principal is considered the more secure approach.

Syntax: true | false

Default: false

LogoutURI

URI path (relative to server host and application context) on that logout (session termination) should be initiated. Use this option for applications without dedicated logout facilities.

Syntax: <URL-path>

Default none

OnLogout

Instruction for how to handle logout if an authentic request was detected accessing the LogoutURI. If OnLogout is not configured, the filter will respond with the simple text/plain-encoded response “session terminated”.

Syntax:

  • redirect: <URL> (respond with a redirect to an fully-qualified or relative URL)
  • dispatch: <URL-path> (respond by dispatching request to a resource before invalidating the session)

Default: none

OnLogin

Instruction for how to handle requests of unauthentic sessions not carrying any tokens. If not set, the filter will either let the request pass (if AuthenticationOptional is enabled), with a BasicAuth challenge (if Header=Authorization) or respond with a 401 “Unauthorized”.

Syntax:

  • redirect: <URL> (respond with a redirect to an fully qualified or relative URL)
  • dispatch: <URL-path> (respond by dispatching request to a resource)

Default: none

JAASAuthentication

Enables propagation of user identity with JAAS means (Subject.doAs()).

Syntax: true | false

Default: false

Integration

Configuring applications to use Nevis Authentication Filter

To activate the NinjaAuthenticationFilter, define the filter in the application web.xml as follows:

<filter>
<filter-name>NinjaAuthenticationFilter</filter-name>
<filter-class>ch.nevis.ninja.filter.NinjaAuthenticationFilter</filter-class>
<init-param>
<param-name>NevisSignerCertificate</param-name>
<param-value>.../path/to/truststore.jks</param-value>
</init-param>
<init-param>
<param-name>LogoutURI</param-name>
<param-value>/sessions/logout</param-value>
</init-param>
<init-param>
<param-name>OnLogout</param-name>
<param-value>redirect:/portal/logout-confirmation.html</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>NinjaAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

The sample configuration defines /sessions/logout as the logout URI. The logout URI is prefixed with the application context root, and you can configure it as LogoutURI in nevisProxy to destroy the HttpSession when the global SSO session is terminated. For further information, see nevisProxy Reference Guide on LogoutURI.

The code for NinjaAuthenticationFilter is distributed both in the ninja-filter and in the ninja-uber packages. Distribute the JAR therein in the application web archive, or add it to the container class path. When using ninja-uber, no further JARs are needed. However, in case of ninja-filter package, the ninja-commons and all other dependencies are to be provided also.

Integration with nevisProxy

To integrate with NinjaAuthenticationFilter, BasicAuth identity propagation needs to be configured in nevisProxy. Ninja expects the secure token as the password, while the user name must match the userid in the token.

Add the following filter to the web.xml of your nevisProxy instance and map it to the path of your application:

<filter>
<filter-name>DelegationFilter</filter-name>
<filter-class>
ch::nevis::isiweb4::filter::delegation::DelegationFilter
</filter-class>
<init-param>
<param-name>DelegateBasicAuth</param-name>
<param-value>
AUTH:user.auth.UserId AUTH:user.auth.SecToken
</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>DelegationFilter</filter-name>
<url-pattern>/myapp/*</url-pattern>
</filter-mapping>

Further Integration Use Cases

The NinjaAuthenticationFilter can be used in several use cases. The following sections describe some of those scenarios and how to deploy NinjaAuthenticationFilter to enable them.

Multiple Authentication Mechanisms

In this scenario, an application needs to allow two different authentication methods for the application resource URLs. Optional X509 client certificate authentication shall be attempted first and Ninja shall be used to perform token-based authentication as a fallback. We assume that there is a filter named CertLoginFilter that performs a login if the request is associated with a trusted and valid transport-layer client certificate and that it forwards the request without action if no such certificate is present.

The NinjaAuthenticationFilter is configured to perform JAAS authentication:

<filter>
<filter-name>NinjaAuthenticationFilter</filter-name>
<filter-class>ch.nevis.ninja.filter.NinjaAuthenticationFilter</filter-class>
<init-param>
<param-name>NevisSignerCertificate </param-name>
<param-value>...../cert.der</param-value>
</init-param>
<init-param>
<param-name>RoleGetters</param-name>
<param-value>TokenRoleGetter</param-value>
</init-param>
<init-param>
<param-name>JAASAuthentication</param-name>
<param-value>true</param-value>
</init-param>
</filter>

… and the filter is mapped on all paths of the application after the CertLoginFilter:

<filter-mapping>
<filter-name>CertLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
<filter-name>NinjaAuthenticationFilterSimple</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

For this simple example, this is enough to implement support for two authentication schemes.

Mixed Anonymous/Authentic Application with Dynamic Enforcement

While many applications are designed to be either public or protected from the start, there are also situations where applications need to allow both anonymous and authentic (non-anonymous) access. Often, the anonymous parts of the application should also be informed about the user identity if the user is known (i.e. authenticated). So each sub-location of the application falls into one of the following three categories:

  • Anonymous sub-locations, where anonymous access is allowed and where requests of authentication do not need to be injected with the context of the user identity. Often, static resources or very simple query services fall under this classification.
  • Semi-anonymous sub-locations, where anonymous access is allowed, but where the access should be in the context of the user identity if the session has been authenticated. There are no declarative rules based on which a login can be enforced because only the application knows whether the request would trigger a switch from an anonymous to an authenticated session. Most pages of shop-like applications are in this category because browsing in anonymous access should be allowed, but once the user is known, additional information should be displayed.
  • Protected sub-locations, where anonymous access is never allowed and where anonymous access attempts always trigger a login-process. In a shop-like scenario, the user-profile and the checkout functionalities are examples for this behaviour.
note

The above classification applies for sub-locations which are recognizable by their request paths. If that is not the case, then the configuration must fall back to the most secure mode that permits the required functionality and the application must dynamically trigger logins where necessary. For example this could be done by the application redirecting to a protected login page.

To enable mixed authentication on an application, nevisProxy needs to be instructed to pass through unauthentic requests. This means that the IdentityCreationFilter can not be mapped on that sub-location.

<filter>
<filter-name>NevisIdmAuthenticationFilter</filter-name>
<filter-class>ch::nevis::isiweb4::filter::auth::IdentityCreationFilter</filter-class>
...
<init-param>
<param-name>StateKey</param-name>
<param-value>MyStateKey</param-value>
</init-param>
...
</filter>

<filter>
<filter-name>OptionalNinjaDelegationFilter</filter-name>
<filter-class>ch::nevis::isiweb4::filter::delegation::DelegationFilter</filter-class>
<init-param>
<param-name>DelegateBasicAuth</param-name>
<param-value>
AUTH:user.auth.UserId AUTH:user.auth.SecToken
</param-value>
</init-param>
<init-param>
<param-name>DelegateSource</param-name>
<param-value>MyStateKey</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/myapp/protected/*</url-pattern>
</filter-mapping>

<filter-mapping>
<filter-name>OptionalNinjaDelegationFilter </filter-name>
<url-pattern>/myapp/*</url-pattern>
</filter-mapping>

The above configuration sets up a protected sub-location on /myapp/protected but allows optional authentication on all other sub-locations of /myapp/*. This is done by not mapping the IdentityCreationFilter in any non-protected sub-locations and by configuring the DelegationFilter to fetch data with MyStateKey even if a request did not pass through an IdentityCreationFilter. The DelegationFilter will not block requests, for which it can not find an authentication state, so that such requests are passed on to the application without BasicAuth header and with token.

Once the nevisProxy configuration is ready, the application can define anonymous, semi-anonymous and protected sub-locations by configuring NinjaAuthenticationFilters accordingly. The configuration example below assumes that the application has a context root of myapp so that the nevisProxy configuration shown above is matched:

<filter>
<filter-name>ProtectedLocationFilter</filter-name>
<filter-class>ch.nevis.ninja.filter.NinjaAuthenticationFilter</filter-class>
<init-param>
<param-name>NevisSignerCertificate </param-name>
<param-value>...../cert.der</param-value>
</init-param>
<init-param>
<param-name>AuthenticationOptional</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter>
<filter-name>SemiAnonymousLocationFilter</filter-name>
<filter-class>ch.nevis.ninja.filter.NinjaAuthenticationFilter</filter-class>
<init-param>
<param-name>NevisSignerCertificate </param-name>
<param-value>...../cert.der</param-value>
</init-param>
<init-param>
<param-name>AuthenticationOptional</param-name>
<param-value>true</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>ProtectedLocationFilter</filter-name>
<url-pattern>/protected/*</url-pattern>
</filter-mapping>

<filter-mapping>
<filter-name>SemiAnonymousLocationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

The above enforces a protected sub-location on protected/ and allows for both anonymous and authenticated access to all other locations. To enforce the authentication of a previously anonymous session, the application might redirect to a sub-location such as /protected/login at which point nevisProxy will trigger an authentication. Or if the user has performed an authentication somewhere else within the SSO-realm already, then the user's identity will become known to all sub-locations of myapp due to the configuration of DelegationFilter and the use of the SemiAnonymousLocationFilter.