Configuration - Common Ninja options and usage
User ID and Roles
- Finding User ID: By default, Ninja propagates the user ID contained in the Token to the container, a
Servlet
callingPrincipal.getName()
will get the user ID which is contained in the Nevis SecToken. If a different field of the token should be used as user ID, aUserGetter
can be configured. - Finding Roles: In addition to setting the user ID, Ninja also sets "Roles" (depending on the container, the container takes these "Ninja roles" and does some additional mapping). By default, Ninja sets the role "member".
Note that the JAAS and Servlet
principal interfaces do not allow listing roles. Instead, the Servlet
specification has methods to test whether a user has a particular role or not. Thus, Java applications which require these roles have to cast the JAAS principal to the NinjaTokenPrincipal
, a class that can provide the roles and offers many options unknown to the bare Java Principal
class.
User Getters
The UserGetter
s allow customisation of the user ID (in Java actually the name of the principal) that is propagated to the application. By default, Ninja uses the TokenUserGetter
that reads the field userId (from SecTokens) or Subject/NameID (from SAML Assertions). The following UserGetter
s are provided by Ninja:
Class Name | Parameters | Notes |
---|---|---|
TokenUserGetter | <no parameters> | Default UserGetter , sets the principal name to userId (when using SecTokens) or Subject/NameID (when SAML Assertions are used). |
AttributeUserGetter | source=<field-name> | Sets the value of a token attribute or field as principal name. |
Custom User Getters
To customise the process of finding the user ID, implement the interface ch.nevis.ninja.commons.mapping.UserGetter
. The constructor must take a single Map<String,String>
in which the configuration parameters will be passed. Place the JAR file containing the code together with all required dependencies in the class path or module of the container.
To activate a custom UserGetter
, specify its full class name in the Ninja configuration in option UserGetter
. Any name/value pairs contained in your UserGetter
configuration are passed to the constructor in the Map
.
Role Getters
RoleGetter
s are responsible for determining a set of roles and propagating them into the JAAS and Servlet
contexts. The Ninja default behavior is implemented by the StaticRoleGetter
setting a single role "member". This minimal default configuration allows easy configuration of authentic and unauthentic zones within the application, irrespective to the roles indicated by received tokens.
The table below shows the available standard role getters:
Class Name | Parameters | Notes |
---|---|---|
StaticRoleGetter | roles=<list separated with ","> | Default role getter, to configure default behavior use: StaticRoleGetter(roles="member") . If no roles or an empty role is specified, the default is used. |
TokenRoleGetter | <no parameters> | Takes the roles from the Nevis SecToken |
EmptyRoleGetter | <no parameters> | Does not set any roles. |
MappedRoleGetter | mappingfile=<path/to/roles-mapping.properties> | Assignes roles according to a mapping of attributes to roles defined in the configured properties file. Entries must have the following syntax: <attribute-name>.<attribute-value> : <role>,<role>… Note that the MappedRoleFilter will split attribute values by commas so that single attribute fields can trigger multiple mapping rules. |
Custom Role Getters
To customize the process of finding roles, Ninja allows implementing custom RoleGetter
s: Implement the interface ch.nevis.ninja.commons.mapping.RoleGetter
. The constructor must take a single Map<String,String>
in which the configuration parameters will be passed. Place the JAR file containing the code together with all required dependencies in the class path or module of the container.
To activate a custom RoleGetter
, specify its full class name in the Ninja configuration in option RoleGetters
. Any name/value pairs contained in the RoleGetter
configuration are passed to your constructor in the Map
.
Logging
Ninja uses SLF4J as a logging facade, which allows seamless integration with any bigger logging framework. To enable Ninja logs next to the web application logs, a binding JAR matching to the logging framework of the web application is to be provided during runtime. Ninja does not provide any concrete logging provider or binding out of the box, this is to be done by the web application integration project itself. See the related chapter of the SLF4J manual.
Ninja uses the ch.nevis.ninja
logger for its log messages, which we recommend to be added to the configuration file of the logging framework used by the web application. After that, configuring Ninja log appenders and log levels can be done the same way as for the web application itself.
Development Mode
Ninja can run in an operation mode which does not require a Nevis access management setup. This is useful in development environments, where focus is set on the application, and maintaining a complete SSO system is both unnecessary and prohibitive for testing. The configuration of the development mode (DevMode) introduces only a minimal modification to a productive Ninja setup, requiring only a few settings in the Ninja configuration block.
Enable the DevMode by setting the Ninja parameter DevMode="true"
and by configuring the following:
- DevDir: Filesystem directory where Ninja stores generated SecTokens and their source properties.
- DevTokenSignerCert: The signer certificate of SecTokens. This is usually identical to NevisSignerCertificate, but exactly one certificate must be identified. Accepts PEM, DER and JKS (with
<file>?alias=<alias>
notation) files. - DevTokenSignerKey: The signer key to use when generating SecTokens. Accepts JKS (with
<file>?alias=<alias>
notation) and PKCS8 encoded DER key files. - DevTokenSignerKeyPassphrase: The passphrase for the signer key. Use
file://<file>
,pipe://<passphrase-getter>
orsecret://<obfuscated-passphrase>
to hide the password from the configuration. - DevPassword: The password the users must provide to use DevMode.
Once DevMode is enabled, an incoming request is processed as follows:
- If no BasicAuth Header is provided, request entry of a password from user with a 401 Basic Auth challenge.
- If a BasicAuth Header has provided a user name and a password, the password is compared to the configured DevPassword.
- If the password is correct, Ninja searches for specific files in the configured DevDir. Ninja searches for the following two files in the configured DevDir:
devmode_<userId>.properties
: contains the properties of the userdevmode_<userId>_generated_sectoken.xml
: contains the last generated SecToken- The user name provided in the BasicAuth header is used to find the properties file. The same user name is checked against the userId in the SecToken generated by DevMode. Use the UserGetter mechanism if the user name in the application should be different from the userId that is be set by Nevis
- If no user properties file was found, Ninja generates a default SecToken for the user, creating the above files in the process.
- If the user properties were found, but no SecToken file or the SecToken file is older than the user properties file, then Ninja regenerates the SecToken according to the user properties, rewriting the SecToken file in the process.
- If the user properties are older than the SecToken file and the SecToken loaded from the file is still valid, then Ninja (re-)uses that SecToken.
- Once a SecToken has been loaded or generated, normal processing is resumed. The token is validated and consumed as usual.
The above procedure allows dynamically adding users simply by logging in initially. Then, the new user's property files can be modified to differentiate them. The default user properties are:
_signAlg=SHA1withRSA
_format=CSSO-1.0
_age=10000
_ttl=62208000
esauthid=Ninja-DevMode
entryid=Ninja-DevMode
domain=NINJA_DEVMODE
userid=<userid>
loginId=<userid>
roles=user
sessid=<timestamp>
authLevel=auth.weak
Properties beginning with an underscore _
modify the metadata fields of the SecToken. The known fields are:
_signAlg
: algorithm of signature_format
: SecToken format_age
: age of SecToken when generated, in milliseconds_ttl
: time-to-live of SecToken, in seconds
All other properties is passed as attributes to the SecToken format builder. Note that depending on the SecToken format, some attributes may be handled as special cases. Removing any of the default attributes is therefore not advised.
Common Configuration Properties
NevisSignerCertificate
The certificate(s) files to be used for verification of the SecToken signature. It is recommended to specify using an absolute path to the file (instead of assuming a current working directory, which is the default).
The file type is determined by the file name extension. The following list shows the supported file formats and extensions.
- .pem: Base-64 encoded x.509 certificate with PEM headers. The certificate file must contain a single certificate only. The certificate file must not contain any comments.
- .der: Single DER encoded x.509 certificate
- .jks: Java Key Store, Ninja uses all certificates in this store to verify the Nevis SecToken, so all certificates in this store must be trusted for this purpose.
Syntax: <filename>,<filename>,...
default: /var/opt/neviskeybox/default/nevis/truststore.jks
RoleGetters
Specifies the Ninja RoleGetter to use to find the roles for the user. Defaults to use the “StaticRoleGetter” with roles=”member”. Alternatively, configure TokenRoleGetter to set the roles found in the SecToken.
A custom RoleGetter can be implemented, see the chapter "Custom RoleGetters" for details.
Syntax: <classname>[“(“ <name>=”<value>” { “,” <name>=”<value>” } “)”]
Default: StaticRoleGetter(roles="member")
This default is also used if “roles” is not specified or empty.
UserGetter
Specifies the Ninja UserGetter.
Syntax: <classname>[“(“ <name>=”<value>” { “,” <name>=”<value>” } “)”]
Default: TokenUserGetter
TokenTolerance
The Nevis SecToken, generated by esAuth has limited validity time. This parameter specifies a tolerance used when verifying this validity time. This value should be only a fraction of the actual token lifetime.
Syntax: <time-out>
Default: 600 (= 10 minutes)
TokenEncoding
When set, this property causes Ninja to correct the encoding of incoming SecTokens and SAML assertions.
This only applies for JAAS login modules, where ISO-8859-1 encoding is enforced by the container and consequently tokens with any other encoding will be garbled. Set this property to the actual encoding of the SecToken or SAML assertion if special characters cause validation of the token to fail.
Syntax: <encoding>
Default: none (no charset-correction is performed)
TokenSourceEncoding
Defines whether the security token is base64 encoded. Used for XML tokens containing newlines.
Syntax: true | false
Default: false
Note that for BasicAuth transport (which is also Base64 encoded), this option must not be set as the Base64-decoding is already implied by the transport protocol.
TokenIsBase64Encoded
Defines whether the security token is base64 encoded. Used for XML tokens containing newlines.
Syntax: true | false
Default: false
Note that for BasicAuth transport (which is also Base64 encoded), this option must not be set as the Base64-decoding is already implied by the transport protocol.
LogDebug
NOTE: This configuration variable is not available for all variants, see specific documentation to enable logging.
Controls logging of container plug-ins and Ninja Session Filter. If set to "true", debug-level tracing information is written to the server log file of the container.
Syntax: boolean
Default: false
DevMode
Activates the development mode of Ninja. See also: the chapter "Development Mode"
Syntax: boolean
Default: false
DevDir
Directory to store user properties and generated SecTokens in DevMode.
Syntax: <path>
Default: none (required if DevMode=true)
DevTokenSignerCert
Signer‘s certificate for SecTokens generated in DevMode. Must specify exactly one certificate.
DER, PEM or JKS files are accepted. Use the following syntax to specify the alias of the certificate entry in a JKS file:<jks-file>?alias=<alias>
Syntax: <path>
Default: none (required if DevMode=true)
DevTokenSignerKey
Signer‘s key for SecTokens generated in DevMode. Must specify exactly one RSA private key.
DER (pkcs8 encoded) or JKS files are accepted. Use the following syntax to specify the alias of the key entry in a JKS file:<jks-file>?alias=<alias>
Syntax: <path>
Default: none (required if DevMode=true)
DevTokenSignerKeyPassphrase
Passphrase of the signer private key for SecTokens generated in DevMode.
Syntax: <passphrase>
or file://<passphrase-file>
or pipe://<passphrase-getter>
or secret://<obfuscated-passphrase>
Default: none (required if DevMode=true)
DevPassword
Password for login using DevMode.
Syntax: <password>
Default: ninja
Accessing the Principal in Applications
The following sections describe how to fetch and work with the user principal from within application code. Many applications do not require information about the authenticated user apart from the user ID and possibly roles associated. However, some use cases necessitate accessing additional attributes of the user identity and/or forwarding the authentication token received.
The basic principle how to do this is always similar:
- Fetch the user principal. How this is done depends on the framework / API used by the application.
- Cast the user principal into a
NinjaTokenPrincipal
. This is the base class into Ninja place the token data and the received and validated token itself. - Use the
NinjaTokenPrincipal
instance to get attributes and to perform additional checks.
The following sections show short code snippets demonstrating this approach for different application technologies.
Using the Servlet API
Using the Servlet API, the principal can be retrieved directly and it can be casted to a NinjaTokenPrincipal
to fetch additional information:
NinjaTokenPrincipal principal = (NinjaTokenPrincipal) req.getUserPrincipal();
// get userID
String userId = principal.getName();
// get token as String, can be forwarded to further token-consuming services
String token = principal.getAuthTokenAsString();
// Attributes contained in security token
Map<String, String> userAttributes = principal.getAttributes();
// Roles contained in security token
String[] roles = principal.getRoles();
Using JSF 2.0
From JSF 2.0, the FacesContext
and the ExternalContext
can be retrieved to get the Principal
. Then it can be casted to a NinjaTokenPrincipal
to get access to further fields:
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext context = fc.getExternalContext();
NinjaTokenPrincipal principal = (NinjaTokenPrincipal) context.getUserPrincipal();
// get userID
String userId = principal.getName();
// get token as String, can be forwarded to further token-consuming services
String token = principal.getAuthTokenAsString();
// Attributes contained in security token
Map<String, String> attributes = principal.getAttributes();
// Roles contained in security token
String[] roles = principal.getRoles();
Developers are advised to pack the above code into a managed bean (for example 'AuthenticatedUser') that can be injected to controllers and views wherever permission checks are in order or token attributes need to be accessed.
Using CDI 2.0 in Java EE6/7 Containers
With CDI 2.0 in Java EE6/7 containers, the principal can be injected directly with the @Resource
annotation:
@Namedpublic class MyBean {
...
@Resource Principal principal;
...
Public String getMyTokenAttribute() {
NinjaTokenPrincipal principal = (NinjaTokenPrincipal) this.principal;
return principal.getAttributes().get(MY_ATTRIBUTE_NAME);
}
...
}
Using JAX-RS 2.0
With JAX-RS 2.0, published methods and resource classes can be protected with the @DenyAll
, @PermitAll
and @RolesAllowed
annotations. To fetch the Principal
, a SecurityContext
can be injected directly to a published method:
@GET
@RolesAllowed({"admin", "group1"})
public String doSomething(@Context SecurityContext context) {
// Get the principal instance
NinjaTokenPrincipal principal = (NinjaTokenPrincipal) context.getUserPrincipal();
// get userID
String userId = principal.getName();
// get token as String, can be forwarded to further token-consuming services
String token = principal.getAuthTokenAsString();
// Attributes contained in security token
Map<String, String> attributes = principal.getAttributes();
// Roles contained in security token
String[] roles = principal.getRoles();
...
}
Using JAX-WS 2.0
In a JAX-WS SOAP service, the principal is retrieved from the WebServiceContext
which in turn can be injected with @Resource
:
@WebService
public class TheWebService {
@Resource
private WebServiceContext context;
...
private NinjaTokenPrincipal getPrincipal() {
return (NinjaTokenPrincipal) context.getUserPrincipal();
}
}