Configuring Alfred Edge

Alfred Edge builds on Spring Boot. Like in Spring Boot, the configuration in Alfred Edge can be externalized, so the same application can be configured differently in different environments. Alfred Edge can be configured using properties files, YAML files, environment variables and command-line arguments.

Properties are considered in the following order, where the first found is used:

  1. Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
  2. Command line arguments.
  3. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
  4. JNDI attributes from java:comp/env.
  5. Java System properties (System.getProperties()).
  6. OS environment variables.
  7. Profile-specific application properties outside of your packaged jar (edge-{profile}.yaml or edge-{profile}.properties).
  8. Application properties outside of your packaged jar (edge.yaml or edge.properties).
  9. The default Alfred Edge application properties packaged inside the .jar in edge.yaml.

In practice this means when running in a new environment, an edge.yaml file can be provided outside of the edge-app.jar that overrides the default settings. Environment- or profile-specific settings can be loaded from edge-{profile}.yaml. For one-off testing, you can launch with a specific command line switch (e.g. java -jar edge-app.jar --server.address.port=8081).

Where these specific application properties files are put, is explained in the Installation Manual.

Configuring Alfred Edge on Tomcat Application Server

Loading in an external configuration when deploying on a Tomcat Application server can be done in two ways.

Deploying in your Tomcat installation folder

When deploying Alfred Edge in Tomcat, you can put your configuration in the ${CATALINA_HOME}/lib/config folder. If you place your configuration in this directory, Alfred Edge will automatically pick it up and load it.

Deploying in a custom directory

When using Tomcat, it is possible to place the configuration in a custom directory. To allow Alfred Edge to find the configuration, add the -Dspring.config.location variable to CATALINA_OPTS. If spring.config.location contains directories (as opposed to files) they should end in / (and will be appended with the names generated from spring.config.name before being loaded, including profile-specific file names). Files specified in spring.config.location are used as-is, with no support for profile-specific variants, and will be overridden by any profile-specific properties. The spring.config.name defaults to edge.

Routes

A basic functionality of Alfred Edge is routing requests to downstream services. This functionility is implemented with Zuul.

The routes are completely defined in the external application configuration file.

The configuration is also explained for Spring.

Simple routing filter

The basic configuration routes requests directly to a fixed url.

Configuration

zuul:
  routes:
    alfresco:
      path: /alfresco/**
      url: http://<alfresco-host>:<alfresco-port>/alfresco
    share:
      path: /share/**
      url: http://<alfresco-host>:<alfresco-port>/share

The above example configuration routes all requests starting with /alfresco to the url http://<alfresco-host>:<alfresco-port>/alfresco and the requests starting with /share to the url http://<alfresco-host>:<alfresco-port>/share

The path parameter is optional. If no path parameter provided, all requests to the service name will map to the url. E.g. following configuration will route all /alfresco/** requests to http://<alfresco-host>:<alfresco-port>/alfresco

zuul:
  routes:
    alfresco:
      url: http://<alfresco-host>:<alfresco-port>/alfresco

Ribbon routing filter

In this kind of setup, Alfred Edge routes requests through Ribbon services.

In such a configuration, the requests can be load balanced over different downstream services.

Configuration

zuul:
  alfresco:
    path: /alfresco/**
    stripPrefix: false
    serviceId: alfresco
  share:
    path: /share/**
    stripPrefix: false
    serviceId: share

alfresco:
  ribbon:
    listOfServers: <alfresco-host-1>:<alfresco-port>, <alfresco-host-2>:<alfresco-port>
share:
  ribbon:
    listOfServers: <alfresco-host-1>:<alfresco-port>, <alfresco-host-2>:<alfresco-port>

The routes for Zuul are defined by the path and get a serviceId, used by Ribbon to find the listOfServers that may receive the requests. The path definition can also include a stripPrefix property. If set true, the forwarded request is the original request, without the matching path definition.

With this example configuration, all traffic to /alfresco/ will be routed to the alfresco Ribbon service. In this example, this is a load balancer between an alfresco1 and alfresco2 host.

By default, ribbon services have a connection- and read timeout of 1000ms. To change this timeout for all services, add following configuration: (time in milliseconds)

ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000

To change this timeout for a specific ribbon service, add following configuration:

<serviceName>:
  ribbon:
    ConnectTimeout: 3000
    ReadTimeout: 60000

Configuring hystrix

The Ribbon router uses Hystrix to recover from latency and dependency failures.

The default timeout for hystrix is 1000ms. Hence when using Ribbon routing, it is possible that this timeout limit is insufficient.

To solve this, we can configure hystrix to

  • disable hystrix timeout globally:
    hystrix.command.default.execution.timeout.enabled: false
  • disable hystrix timeout on service level:
    hystrix.command.<serviceName>.execution.timeout.enabled: false
  • set hystrix timeout globally:
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
  • set hystrix timeout on service level:
    hystrix.command.<serviceName>.execution.isolation.thread.timeoutInMilliseconds: 60000

Authentication

The authentication system in Alfred Edge requires requests passing through to be authenticated. Alfred Edge can act as a central authentication point in the system architecture. User identity can be securely propagated to the backend services, with a secure & signed JWT token.

Integration with a range of authentication systems is available. Currently the following authentication systems are fully supported:

  • LDAP
  • Active Directory (aka LDAP-AD)
  • In memory user-store
  • Alfresco
  • Kerberos

If integrating Alfred Edge with only one of these systems is not sufficient, multiple authentication protocols can be combined together. Multiple instances of the same authentication protocol can also be combined, if for example your authentication architecture requires multiple LDAP-servers to be consulted.

Authentication and identity management functionality is provided by a prioritized list, or chain, of configurable authentication protoocols. The built-in authentication chain is a priority-ordered list of authentication system instances.

An authentication system provides the following functionality to Alfred Edge:

  • Authenticate a (web-)request, usually by veryfying user credentials
  • Provide information about the users’ role or group

It is NOT possible to use Alfred Edge to authenticate CIFS or IMAP protocols.

LDAP

Overview

LDAP is often used by organizations as a central repository for user information and as an authentication service. It can also be used to store the role information for application users.

Alfred Edge uses Spring Security & Spring LDAP internally to support many different LDAP configuration scenario’s.

Using LDAP with Spring Security

LDAP authentication in Spring Security can be roughly divided into the following stages.

  • Obtaining the unique LDAP “Distinguished Name”, or DN, from the login name. There are two scenario’s supported:
    • If the exact mapping of usernames to DNs is known in advance, this can be a straight forward user-DN-pattern, such as uid=joe,ou=users,dc=example,dc=com.
    • Otherwise this will mean performing a search in the directory.
  • Authenticating the user by “binding” as that user.
    • Spring Security supports performing a remote “compare” operation of the user’s password against the password attribute in the directory entry for the DN.
  • Loading the list of authorities for the user.

Configuring LDAP Authentication

These properties should be defined:

  • authentication.ldap.server.url: the url of the LDAP server(s).
  • authentication.ldap.server.base: the base suffix from which all operations should origin. If a base suffix is set, you will not have to (and, indeed, must not) specify the full distinguished names in any operations performed.
  • authentication.ldap.server.authentication: the authentication used for the connection to the LDAP server. Following values are defined:
    • simple : the default value for plain ldap encryption
    • start-tls: the authentication encryption is started with TLS.

Example:

authentication:
  ldap:
    server:
      url: ldap://<ldap-server>:<ldap-port>
      base: dc=example,dc=com
      authentication: start-tls 

Using Bind Authentication

This is the most common LDAP authentication scenario.

authentication:
  ldap:
    user-dn-pattern: uid={0},ou=people

This simple example obtains the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. This is OK if all your users are stored under a single node in the directory.

If instead one wishes to configure an LDAP search filter to locate the user, you could use the following:

authentication:
  ldap:
    user-search-filter: (uid={0})
    user-search-base: ou=people

If used with the server definition above, this would perform a search under the DN ou=people,dc=example,dc=com using the value of the user-search-filter attribute as a filter. Again the user login name is substituted for the parameter in the filter name, so it will search for an entry with the uid attribute equal to the user name. If user-search-base isn’t supplied, the search will be performed from the root.

User Name

By default the user name used in Alfred Edge and for the subject claim in the JWT Token, is the user name specified by the user in the login panel. That user name, together with the supplied password is used for authentication on the LDAP server.

In special cases, however, the configuration wants another attribute of the LDAP user definition to be used as user name and subject. This can be done by specifying the property user-name-attribute.

authentication:
    ldap:
        user-name-attribute: cn

Loading Authorities

The LDAP repository is not only used for user authentication, but also for user authorization.

The authorization is based on the groups the user is defined in. To define the rules where the groups are searched for, following properties can be specified:

authentication:
  ldap:
    group-search-filter: uniqueMember={0}
    group-search-base: ou=groups
    group-search-tree: true

The parameter group-search-filter defines the rule that checks that a user {0} belongs to a group.

The parameter group-search-base is the base from where groups are searched for and the parameter groupSearchTree allows or forbids a tree search (default value is false which forbids the tree search). In a tree search, the groups are searched hierarchically below the search base, else only one the level of the search base.

It is possible to map for the defined groups one or more roles. In this case, the user is granted all the roles linked to the groups the user belongs to.

authentication:
  ldap:
    group-mapping:
      - group: managers
        roles: EDGE_ADMIN
      - group: submanagers
        roles: ADMIN,TEST
      - group: developers
        roles: ACTUATOR,TEST

If no group mapping is added, the user gets roles equal to the group names of the groups he belongs to.

LDAP on Active Directory

The Microsoft Active Directory has its own authentication mechanism, that differs from the LDAP-standard.

Typically authentication is performed using the domain username (in the form user@example.com), rather than using an LDAP distinguished name. To make this easier Alfred Edge has explicit Active Directory authentication support, which is a customized version of the more generic and standardized LDAP authentication.

If the ldap-ad authentication system is properly configured, a user can log in with its username or with his full AD principal name (user@example.com).

Configuring LDAP-AD Authentication

The domain and url configuration parameters are required to configure the ldap-ad authentication system.

  • The domain: when a user logs on with its user name, the AD principal name for this user will be constructed by appending the domain. For example: if the domain property is configured to example.com and a user will login with username sharon, Alfred Edge will use sharon@example.com to authenticate against AD.
  • The url: this specifies the ldap://-url where the Active Directory server can be accessed.
  • the base-dn: (optional) this is the root for the search when locating the user-object. This parameter is optional and by default this is automatically derived from the domain.

Example configuration:

authentication:
  chain:
    - ad1:ldap-ad
  ad1:
    domain: mydomain.com
    url: ldap://<ldap-ad-host>
    base-dn: dc=example,dc=com

User name

By default the user name used in Alfred Edge and for the subject claim in the JWT Token, is the user name specified by the user in the login panel. That user name, together with the supplied password is used for authentication on the LDAP-AD server.

In special cases, however, the configuration wants another attribute of the LDAP user definition to be used as user name and subject. This can be done by specifying the property user-name-attribute.

authentication:
    ad1:
        ...
        user-name-attribute: sAMAccountName

Kerberos Authentication

Overview

Kerberos is a commonly used system for authentication on company networks. On Windows it is the default authentication for the Active Directory.

Configuring Kerberos Authentication

Add in the authentication chain one entry of the type kerberos. Due to system wide settings, only one kerberos authentication definition at a time can be set up.

authentication:
  chain:
    - kerberosAD:kerberos

  kerberosAD:
    debug: false
    krb5-location: <path-to-krb5-config>

When debug is set, the kerberos module logs its complete debug information. Switch it off for production systems.

For the configuration of the kerberos, the location of a kerberos file is specified.

This file is read by the kerberos module itself, and in mixed environments its name must be readable on both windows and *nix systems, so use “\” as path delimiter.

This kerberos configuration file is described in here.

In our setup, the name of the kdc and admin servers for the realm are specified:

[realms]
EXAMPLE.COM = {
    kdc = <ldap-ad-host>
    admin_server = <ldap-ad-host>
}

If needed, the standard UDP protocol used for communication with the kerberos servers, can be replaced by TCP when setting this parameter:

[libdefaults]
...
udp_preference_limit = 1

This may be necessary when network configuration does not allow the UDP connection.

Kerberos with Single Sign On

When the kerberos is not only used for plain authentication, but also with single sign on, the name of the service principal and the path to the keytab file are specified.

  kerberosAD:
    debug: false
    krb5-location: <path-to-krb5-config>
    key-tab-location: <path-to-krb5-keytab>
    service-principal: HTTP/<service-principal-edge>@EXAMPLE.COM
    single-sign-on-enabled: true

The keytab file is generated on the kerberos server and contains the key for the service principal. The service principal is specific for the server Alfred Edge is running on.

Service principal is created on the kerberos server, following e.g. this scenario.

Client Configuration for Single Sign On

The browsers, used by the customers to access the application, must be configured to enable single sign on. This link describes how to do it.

Kerberos with Authorization Provider

It is possible to use the Kerberos with an LDAP authorization provier to retrieve the authorities for the user that connects to Alfred Edge.

For other authentication methods, retrieving the user authorities, thus the permissions the user has to perform some actions, are retrieved at once from that authentication provider.

For Kerberos, only the authentication is done, thus verifying the user and its specified password. To retrieve the permissions the user has to perform some actions, an authorization provider is used. This provider gets the roles of the user by reading this information from a database. Currently only one type of authorization provider is defined, i.e. a provider that gets the information from an LDAP repository.

When a user is logged in, the authentication module retrieves the groups the user belongs to via an LDAP request to the Active Directory. To specifiy the parameters for this LDAP connection, an LDAP user and an LDAP-AD block of properties need to be defined. The definition of these authorization providers is found in a next chapter. In the Kerberos definition in the authentication chain, the name of the authorization provider (aka user details provider) is specified.

  kerberosAD:
    debug: false
    krb5-location: <path-to-krb5-config>
    key-tab-location: <path-to-krb5-keytab>
    service-principal: HTTP/<service-principal-edge>@EXAMPLE.COM
    single-sign-on-enabled: true
    user-details-provider : <name-of-the provider>

Creating keytab files on Windows

The creation of service principal and its keytab file on Windows Kerberos AD is explained in this Alfresco Document.

$ ktpass -princ <service-principal>@<realm> -pass <password> 
              -mapuser <domain>\<windows user> 
              -crypto all 
              -ptype KRB5_NT_PRINCIPAL 
              -out keytab_sp.keytab -kvno 0

$ setspn -A <servicePrincipal> <windows user>

$ ktpass -princ <ldapUser>@<realm> -pass <password>  
              -crypto all 
              -ptype KRB5_NT_PRINCIPAL 
              -out keytab_sp_ldap.keytab 
              -in svc_keytab_sp.keytab -kvno 0

(in the snippet the line is split into multiple lines to make it completely visible)

In Memory User Authentication

The “In Memory User Authentication” is an internal authentication system, which makes it possible to authentication against a preconfigured user registry.

This authentication system is primarily intended for testing purposes.

Configuring In Memory Authentication

The in memory user authentication configuration will be explained based on following example configuration.

authentication:
  chain:
    - mem1:mem
    - mem2:mem
  mem1:
    encoder:
      type: bcrypt
    default-roles: USER, INFLOW_ADMIN
    users:
      - id: user-1
        password: $2a$10$qWbu.Kt1wiQNTRkQeAebzul1osGIA27zBjXQHOcn4Hslg/xe2nqNu
        roles: ADMIN
  mem2:
    encoder:
      type: plaintext
    default-roles: USER, INFLOW_ADMIN
    users:
      - id: user-2
        password: password
        roles: ADMIN
Enabling the in memory user authentication

To enable the in memory user authentication, we need to add an authentication of type mem to the authentication chain.

Encoder

The encoder type specifies which encoder is used to encrypt the password of the users.

Supported encoder types:

If no encoder configuration is specified, the default encoder (bcrypt) will be used.

DefaultRoles

This configuration specifies the default roles that are applicable for all users of this in memory user registry.

Users

Specify all the users of this in memory registry. Each user has an id and a password that should be encrypted according to the configured encoder. Additionally a user can have roles.

Alfresco Authentication

This authentication system delegates the authentication to an existing Alfresco system.

The intended use case is to support the migration from an existing Alfresco system to Alfred Edge, where the user-database is managed in Alfresco.

Working Principles

When a user provides credentials in the request to Alfred Edge, this authentication system will use those credentials to request an authentication token (alf_ticket) from Alfresco. If Alfred Edge is able to get an authentication ticket, the user is considered authenticated in Alfred Edge.

This authentication system uses the /service/api/login endpoint to verify the credentials and request and authentication ticket.

Configuring Alfresco Authentication

In edge.yaml in Alfred Edge:

authentication:
  chain:
    - alfresco1:alfresco
  alfresco1:
    server: http://<alfresco-host>:<alfresco-port>/alfresco

To configure the Alfresco authentication:

  1. Create an Alfresco configuration block (alfresco1 in the example).
    The only thing that needs to be configured is the server. The value is the url of the Alfresco server that should be used for the authentication. This server url should end with /alfresco.
  2. Add the Alfresco authentication to the authentication chain.

Note: to make this authentication schema to work properly, the authentication.chain in Alfresco needs to be configured with at least one other (username/password-based) authentication subsystems.

For example (in alfresco-global.properties):

authentication.chain=external-jwt:external,alfrescoNtlm1:alfrescoNtlm

Authorization

In order to define the user details providers (aka the authorization providers), that retrieve the permissions a user has, the configuration file for Alfred Edge contains an ‘authorization section’ with the defined providers, and for each provider its configuration.

User Details Providers

Since user details providers can be built on different types of database, its type is defined in the list of providers, and the configuration of the these providers can differ for the different types.

Currently, only one type of providers is defined, i.e. ldap.

authorization:
    providers: 
        - <name>:<type>
        - <name>:<type>

Ldap User Details Providers

The first (and only) type of user detailed providers is ldap, to retrieve the user details from an LDAP repository. The same type can be used for plain LDAP and for LDAP on Active Diretory for MicroSoft repositories.

  <name>:
    bind-user: <DN for the user, on which behalf the LDAP connection is set up>
    bind-password: <password>
    url: <url of the LDAP repository>
    authentication: <simple | start-tls>
    base-dn: <base DN for the users in the ldap repository>
    user-search-base: <search base for users in ldap repository>
    user-search-filter: <user search filter>
    user-name-attribute: <optional: attribute used as username>
    group-search-base: <search base for groups in ldap repository>
    group-search-filter: <group search filter>
    group-search-tree: <true | false>
    group-mapping: 
      - group: <group name>
        roles: <list of roles for members of given group>
      - group: <group name>
        roles: <list of roles for members of given group>

Following properties can be set to configure the LDAP user details provider:

  • bind-user: distinguished name of the user on which behalf the connection to the LDAP Repository is made;
  • bind-password: password of that user;
  • url: url of the LDAP repository. Is a comma separated list of urls to the LDAP repository;
  • authentication: the authentication method used to the LDAP repository. Can be simple, the default value or start-tls for authetication that starts with TLS;
  • base-dn: the base for the distinguished names in the repository;
  • user-search-base: search base to find the users in the repository;
  • user-search-filter: filter to search users with;
  • user-name-attribute: optional property. If specified, the value of the named attribute is used internally as user name and subject in the JWT Token.
  • group-search-base: search base to find the groups in the repository;
  • group-search-filter: filter to search groups a user belongs to;
  • group-search-tree: true (default value) if hierarchical search in tree of groups is allowed
  • group-role-attribute: the attribute of the groups distinguished name that is used as authority. Default value is cn;

An example to make it clear:

  ldap-extern:
    bind-user: uid=admin,ou=system
    bind-password: ****
    url: ldap://<ldap-server>:<ldap-port>/
    base-dn: dc=example,dc=com
    user-search-base: ou=people
    user-search-filter: (uid={0})
    group-search-base: ou=groups
    group-search-filter: (&(objectClass=groupOfUniqueNames)(uniqueMember={0}))
    group-mapping:
      - group: managers
        roles: USER, ADMIN, ACTUATOR
      - group: developers
        roles: USER, EDGE_ADMIN, ACTUATOR

JWT Configuration

Alfred Edge passes the authenticated user, his roles and some other information via a JWT Token to the downstream servers.

This example shows the different settings for the JWT Configuration:

filter:
  jwt:
    header:
      name: Authorization
      schema: Bearer
    algorithm: HS256 # HS256 or RS256
    secret: <shared-secret> # Only used with alg HS256
    keystore: # Only used with alg RS256
      path: <path to keystore>
      password: <keystore password>
      alias: <keystore alias>
    claims:
      expiration:
        delay: 60  # default value
      role.enabled: false

The properties filter.jwt.header.name and filter.jwt.header.schema define how the JWT token is put in the header of the forwarded requests. Keep the given values, which are the default values.

The filter.jwt.algorithm can be HS256 or RS256. The algorithm determines how the signature of the token is created. It is hashed with the shared secret or with the private key of the emitter. The signature is verified by the receiver and if not correct, the token is not accepted and the received request rejected.

  • HS256 (use the shared secret): the value filter.jwt.secret must be set to the shared secret between Alfred Edge and the downstream services.
  • RS256 (use the private key): the different filter.jwt.keystore properties must be specified.

The property filter.jwt.claims.expiration.delay specifies the delay for the expiration date put in the JWT Token. It is a value in seconds and the default is 60 seconds. When a service receives messages with JWT Token after the expiration date, they will be disgarded.

The property filter.jwt.claims.role.enabled is used to enable or disable the role claims in the jwt token. If set true, the default value, the JWT Token contains the roles the user has. If set false, these roles are not put in the token. Putting the roles in the JWT Token makes only sense if the downstream services handle them.

Security & Authorization

Path Authorization

Alfred Edge can be configured to require authorization to access certain paths. Only users that are granted a specified authorization role will be able to access this path.

To specifiy the authorization required for a user to request an URL via the Edge API Gateway, following parameters can be added to the configuration:

websecurity:
  login:  /login
  requests:
    - paths: /login, /error, /images/**, /css/**, /fonts/**
      authorization: PERMIT_ALL
    - paths: /zipkin/**
      authorization: ROLE
      roles: EDGE_ADMIN

The property websecurity.login specifies the path of the Login screen. The value /login is the default value.

For the other requests, one can specify the matching URLs and the needed authorization. Paths are specified by Ant-style patterns:

  • ? matches one character
  • \* matches zero or more characters
  • ** matches zero or more directories in a path.

Remark that patterns ending with /** are optimized to be checked with a substring.

The requests are checked in the given order. For the requests that are not matched, the user needs to be fully authenticated.

If no requests at all are configured, then the default paths for login, error, images and fonts are permitted for all. Also all other requests need a fully authenticated user.

The defined authorizations are:

  • PERMIT_ALL the paths can be accessed without any authorization
  • DENY_ALL the paths are forbidden for all
  • ROLE the user needs a role from the given list of roles
  • AUTHORITY the user needs an authority from the given list of authorities
  • FULLY_AUTHENICATED the user needs to be fully authenticated to access the paths.

Security Headers

To avoid that Zuul strips the security headers from the responses from the downstream services, the zuul.ignoreSecurityHeaders must be set false.

The WebSecurity on the classpath of Alfred Edge will put its default security headers in the responses from the downstream services. See Spring Security

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

The external configuration of Edge allows to change this behaviour.

To avoid any security header to be added or modified by Edge, disable the default header behaviour, by setting the property use-defaults to false and not specifying properties for the specific headers:

websecurity: 
    headers:
        use-defaults: false

To complete or change the headers returned by the downstream services, following options exist:

websecurity:
  headers:
     use-defaults: true
     frame-options: DISABLE
     content-security-policy: frame-ancestors 'self'
     cache-control-enabled: true
     x-xss-protection: BLOCK

When the option use-defaults is set false (its default value), all default behaviour of Spring Web Security headers is disabled. If set true, the default headers are generated with the default values, except if for some header a more specific configuration is added.

The option frame-options specifies the X-Frame-Options header. Allowed values are

  • DISABLE: disable the generation of the header,
  • DENY: specify the value DENY for the header, denying the page displayed in a frame,
  • SAME_ORIGIN: specifyi the value SAMEORIGIN for the header, allowing to display it in a frame on the same origin as the page itself.

The option content-security-policy specifies the value for header Content-Security-Policy.

The option cache-control-enabled specifies the Cache-Control header.

Allowed values are false and true.

The option x-xss-protection specifies the X-XSS-Protection header.

Allowed values are

  • ENABLED: enable the XSS Filtering,
  • DISABLED: disable the XSS filtering,
  • BLOCK: enable the XSS Filtering with mode block,
  • DISABLE: disable the writing of the XSS Filtering.

Access Logs

The access logs show the processed requests. The content and the format of this logging can be configured.

Configuration

Running on the embedded tomcat:

server:
  tomcat:
    accesslog:
      enabled: true
      pattern: '%t %{username}r "%r" %s (%B bytes; %D ms)'

Deployed on a tomcat server:

 <Engine name="Catalina" defaultHost="localhost">
   <Host name="localhost"  appBase="webapps"
         unpackWARs="true" autoDeploy="true">
     <Valve className="org.apache.catalina.valves.AccessLogValve" 
       directory="logs"
       prefix="localhost_access_log" suffix=".txt"
       pattern=
  "%t %{username}r &quot;%r&quot; -> %{route-uri}r %s (%B bytes; %D ms)"/>

   </Host>
</Engine>

Standard pattern identifiers are explained in the Tomcat Documentation.

Following specific Edge attributes can also be used in the pattern:

  • %{username}r to log the name of the authenticated user,
  • %{route-uri}r to log the complete uri that will be processed by the target server,
  • %{service-id}r to log the service id, specified in the zuul route that matches the received request,
  • %{route-host}r to log the host to which the request if forwarded.

The attributes route-uri and service-id are available for routes defined with Ribbon and Hystrix, thus where the route is specified by a serviceId. The attribute route-host is available for routes defined with a target url.

When Edge runs on its embedded tomcat server, properties to specify the tomcat behaviour, including the properties for the access log, are specified in the application properties. These properties can be found in the Spring Boot Documentation. All Tomcat specific properties have a name starting with server.tomcat.

When Edge runs on a tomcat server, the access log pattern is to be specified in the tomcat configuration, e.g. in the server.xml file on the tomcat configuration map, as specified in Tomcat Documentation.

Zipkin Logging

In order to check the correct behaviour of the Alfred Edge server and the servers behind this API Gateway, a centralized logging system is setup. It can be used the visualize the parts of the complete system causing some latency, discover the dependencies in the system, …

In order to collect this information, a Zipkin server must be installed and the Alfred Edge API Gateway and other servers must send their information to it.

The collected information can be inspected by the Web UI defined on the Zipkin server.

Configuration

In the Alfred Edge property file, the target Zipkin server must be defined and the collection of data must be enabled.

The collection of data is enabled by 2 components:

  1. Sleuth: Adds the necessary header id in the requests to link the logging from the different servers together,
  2. Zipkin: Creates and sends the spans which allows the Zipkin server to due the latency analysis

To enable both components, following properties are added:

spring:
  zipkin:
    baseUrl: http://<zipkin-host>:<zipkin-port>
    enabled: true  
  sleuth:
    sampler:
      percentage: 0.1 # 10% of messages sampled
    enabled: true

For the Zipkin server the url of the server is specified. To disable the zipkin collection of spans the spring.zipkin.enabled flag must be set false.

For the Sleuth component, the percentage of sampled messages can be specified. 1.0 means 100% and 0.1 is the default value. To disable the Sleuth component the spring.sleuth.enabled flag must be set false.

To let the users access the Zipkin Server for making their analysis, a Zuul Route is specified in Alfred Edge. This allows the users to access these data via the Edge API Gateway.

zuul:
    routes:
    ...
    zipkin:
        url: http://<zipkin-host>:<zipkin-port>/zipkin/

Make sure the / is added at the end of the url!

General Spring Configuration

Since Alfred Edge is a Spring application, a lot of general Spring configuration settings are applicable.

Maximum file and request size

spring:
  http:
    multipart:
      max-file-size: 20MB
      max-request-size: 20MB
  • max-file-size specifies the maximum size permitted for uploaded files. The default is 1MB.
  • max-request-size specifies the maximum size allowed for multipart/form-data requests. The default is 10MB.

Logging

It is possible to increase or decrease the logging level of the software packages used.

This can be done by specifying properties in the yaml file, having the name logging.level.<package> and a value from this list, specifying them from a lot of logging to as little as possible logging

  • TRACE,
  • DEBUG,
  • INFO,
  • WARN,
  • ERROR,
  • FATAL.

A few examples to show the possibilities:

logging.level.org.springframework.security: INFO
logging.level.eu.xenit.alfred.edge: ERROR
logging.level.eu.xenit.alfred.edge.filters.pre: WARN

or

logging.level:
  org.springframework:
      security: WARN
      security.ldap: DEBUG
      security.ldap.userdetails: INFO
      security.kerberos.authentication: TRACE
  eu.xenit.alfred:
        edge: ERROR
        edge.security: DEBUG
        edge.filters.pre: WARN
        edge.jwt.claims.provider: INFO

Metrics Configuration

Alfred Edge can collect a lot of measurement values (aka metrics) and publish them.

By default these metrics are available via the

  • actuator/metrics endpoint
  • JMX Bean viewer
  • via a Graphite agent, displayable via a Grafana UI

If needed, other metrics registry systems can be added on the classpath, to allow other metrics systems. The complete list can be found on Spring metrics.

General Setup

The default setup for the metrics is one central Grafana stack, containing

  • a Carbon database to persist the metrics info,
  • a Graphite api,
  • a Grafana webserver for the User Interface.

Different Alfred Edge applications can send their data to this central Grafana system.

Sampled Metrics

By default Alfred Edge, being a Spring Boot application, will sample a lot of metrics on

  • the system: cpu load, cpu count, …
  • the process: uptime, …
  • the Java Virtual Machine: memory, garbage collection, threads, …
  • the Tomcat: requests (count, time), …
  • the routing, via zuul, hystrix, …

Internally the metrics have a name and are tagged with some values. When exposed the names and tags are combined to give an unique name to the value.

Hystrix Dashboard

Alfred Edge itself is enabled to show a Hystrix Dashboard with the load on the different zuul routes it is sending requests to using the Hystrix Circuit Breaker, thus for the routes defined by a serviceId and a ribbon list of servers in the configuration file.

To display the dashboard:

  • browse to the page http://<edge-server>/hystrix,
  • give the name of the stream: http://<edge-server>/actuator/hystrix.stream,
  • click the Monitor Stream button.

A dashboard with the different routes and their load shows up.

Hystrix
Dashboard

Remark that Zuul does not use thread pools and this makes the lower part left empty.

More information on this dashboard is available on Hystrix Dashboard.

Metrics Configuration in Alfred Edge

Via Grafana UI

In order to make Alfred Edge send the metrics to a graphite agent, like the Carbon database, following settings can be defined in the Edge configuration file (edge.yml)

management.metrics.export:
      graphite:
        host: carbon
        port: 2004 
        enabled: true  
        step: 10s      
        tagsAsPrefix: host,app 

These properties are set:

  • host: the host computer where the graphite agent is running, e.g. the host with the Carbon database
  • port: port number where the graphite agent accepts the batches with values (in the pickle format)
  • enabled: set true to make Edge send the information, default value is false
  • step: the step (period) that the information is sent (10s = 10 seconds, use s for seconds, m for minutes). The value of the step must be equal to the step set in the graphite agent, to avoid null values in the Grafana graphs and tables
  • tagsAsPrefix: specify the tags that are put in front of the metrics names. Use host and app, to make sure that all metrics names in Grafana start with the application name (specified by the property spring.application.name) and the name of the host edge is running on. This introduces extra dimensions to enable displaying information of one specific Edge instance or to group them together.

Grafana

More information on how to configure these Grafana dashboards follows in a following chapter.

Via JMX

No specific setup is needed in Edge.

If the Micrometer JMX Registry artifact is on the classpath, the metrics are visible in the bean metrics via a JMX Client (e.g. Java Mission Control) that can access the Edge application.

JMX Client

Via Actuator Metrics Endpoint

No specific setup is needed in Edge.

The information is available via the /actuator/metrics endpoint for users having the ACTUATOR role.

Actuator
Endpoint

Grafana Dashboards

With the Grafana UI one can define dashboards to visualize the metrics. Detailed information is found on Grafana Documentation

Simple Count or Process-time Graph

Interesting metrics to display are the number of requests processed by Edge.

The most easy graph to add can display the count of successful requests (status 200) to one origin server:

Successful Alfresco
Calls

To select the metric, define such a query, via the query bar.

  • edge : the application name
  • xxx : the host Edge is running on
  • httpServerRequests : name of the metric
  • exception
  • None : select the counts where no exception is thrown
  • method
  • * : select all http methods (get, post, …)
  • status
  • 200 : only status 200 calls
  • uri
  • *alfresco* : all calls with alfresco in the uri
  • count : name of the metric (gives the exact number of requests matching the criteria: it is an incrementing value, reset to zero when the application is restarted.

As shown in the above image, a second line is added in the graph, with the same metric, but with the function derivative() applied on it. This line gives the difference between two consecutive values of the count and is a better representation of the load of the system.

It is also possible to use other metrics instead of count

  • m1_rate : the rate of requests per second, calculated for the last minute
  • m5_rate : the rate of requests per second, calculated for the last 5 minutes
  • m15_rate: the rate of requests per second, calculated for the last 15 minutes

For these requests it is also possible to plot the time to process the requests. Instead of count, use the following metrics:

  • min: the minimum processing time
  • max: the maximum processing time
  • pxx: the percentiles for xx being 50, 75, 95, 98, 99 and 999

Some other statistical values are available.

Combined Graphs

It is possible in Grafana to combine different measures.

E.g. count the number of requests with a return code in the range 400 to 499 (same applies to 300-399 or 500-599 for the different status ranges)

Calls counted per
status

To create the query, select:

  • edge : the app
  • xxx : the host edge is running on
  • httpServerRequests : name of the metric
  • exception
  • None : select the counts where no exception is thrown
  • method
  • * : select all http methods (get, post, …)
  • status
  • 4** : only status calls returning an error status between 400 and 499
  • uri
  • * : all calls
  • count : name of the metric (gives the exact number of requests matching the criteria), which increment until the service is restarted

Apply the function sumSeries() on it and all counts are added to one value and displayed as the increasing number of errors.

Or apply the functions sumSeries() and derivative() on it to display the total number of errors for the last sample.

By adding alerts on the last values with derivative() having a value greater than 0, will alert when errors occur.