Securing your application

To use Spring Security with a Single Web Page Application, like the ones generated by JHipster, you need Ajax login/logout/error views. We have configured Spring Security in order to use those views correctly, and we generate all the JavaScript and HTML code for you.

By default, JHipster comes with 2 different users:

  • “user”, who is a normal user with “ROLE_USER” authorization. The default password is “user”
  • “admin”, who is an admin user with “ROLE_USER” and “ROLE_ADMIN” authorizations. The default password is “admin”

The two authorizations “ROLE_USER” and “ROLE_ADMIN” provide the same access to the entities which means that a “user” is authorized to perform the same CRUD operations as an “admin”. This behavior can be an issue when the application will go to production because a “user” can for example delete any entities. More details on how to improve the access-control can be found on this blog post.

For security reasons, you should change those default passwords in production.

JHipster provides 4 main security mechanisms:

  1. JSON Web Tokens (JWT)
  2. Session-based authentication
  3. OAuth 2.0 and OpenID Connect
  4. JHipster User Account and Authentication (UAA) (which has a separate documentation page as this is more complex)

JSON Web Tokens (JWT)

JSON Web Token (JWT) authentication is a stateless security mechanism, so it’s a good option if you want to scale your application on several different servers.

Please note that this is the default option when using a microservices architecture.

This authentication mechanism doesn’t exist by default with Spring Security, it’s a JHipster-specific integration of the Java JWT project.

This solution uses a secure token that holds the user’s login name and authorities. As the token is signed, it cannot be altered by a user.

Securing JWT

  • JHipster uses a secret key, which can be configured using two Spring Boot properties: jhipster.security.authentication.jwt.secret and jhipster.security.authentication.jwt.base64-secret. The second option uses a Base64-encoded string, so it is considered more secured and thus it is recommended. If both properties are configured, the secret property (less secured) will be used, for legacy reasons. A warning will be shown at application startup if you don’t use the Base64 property.
  • Those keys should have a minimum length of 512 bits: if they are not long enough, you will not be able to use them to login. If that happens, there will be a clear warning at the console to explain that issue.
  • The secret keys are configured in the application-*.yml files. As those keys must be kept secret, you should store them in a secure way for your production profile. It can be set up using the usual Spring Boot property configuration: using a Spring Cloud Config server like the JHipster Registry (our recommended option), using an environment variable, or even a specific application-prod.yml file which is SCP’d by a sysadmin into the same directory as your application’s executable WAR file.
  • You should change the default “user” and “admin” passwords. The easiest way to do this is to deploy your application, login as “user/user” and then “admin/admin”, and for each of them use the “Account > Password” menu to change the password.

Session-based authentication

This is the “classical” Spring Security authentication mechanism, but we have improved it quite significantly. It uses the HTTP Session, so it is a stateful mechanism: if you plan to scale your application on multiple servers, you need to have a load balancer with sticky sessions so that each user stays on the same server.

Securing Session-based authentication

  • For remember-me authentication, the remember-me key is configured in the application-dev.yml and application-prod.yml files, as the jhipster.security.remember-me.key property. As this key must be kept secret, you should store it in a secure way for your production profile. It can be set up using the usual Spring Boot property configuration: using a Spring Cloud Config server like the JHipster Registry (our recommended option), using an environment variable, or even a specific application-prod.yml file which is SCP’d by a sysadmin into the same directory as your application’s executable WAR file.
  • You should change the default “user” and “admin” passwords. The easiest way to do this is to deploy your application, login as “user/user” and then “admin/admin”, and for each of them use the “Account > Password” menu to change the password.

Improved remember-me mechanism

We have modified the Spring Security remember-me mechanism so that you have a unique token, that is stored in your database (SQL or NoSQL database, depending on your choice during generation!). We also store more information than the standard implementation, so you have a better understanding of where those tokens come from: IP address, browser, date… And we generate a complete administration screen, so that you can invalidate sessions, for example if you forgot to log out on another computer.

We have added a very complete cookie theft protection mechanism: we store your security information in a cookie, as well as in the database, and each time a user logs in we modify those values and check if they have been altered. That way, if a someone ever steals your cookie, they will be able to use it only once, at most.

OAuth2 and OpenID Connect

OAuth is a stateful security mechanism, like HTTP Session. Spring Security provides excellent OAuth 2.0 and OIDC support, and this is leveraged by JHipster. If you’re not sure what OAuth and OpenID Connect (OIDC) are, please see What the Heck is OAuth?

Keycloak

Keycloak is the default OpenID Connect server configured with JHipster.

To log into your application, you’ll need to have Keycloak up and running. The JHipster Team has created a Docker container for you that has the default users and roles. Start Keycloak using the following command.

docker-compose -f src/main/docker/keycloak.yml up

If you want to use Keycloak with Docker Compose, be sure to read our Docker Compose documentation, and configure correctly your /etc/hosts for Keycloak.

The security settings in src/main/resources/config/application.yml are configured for this image.

spring:
  ...
  security:
    oauth2:
      client:
        provider:
          oidc:
            issuer-uri: http://localhost:9080/auth/realms/jhipster
        registration:
          oidc:
            client-id: web_app
            client-secret: web_app

Keycloak uses an embedded H2 database by default, so you will lose the created users if you restart your Docker container. To keep your data, please read the Keycloak Docker documentation. One solution, with keeping the H2 database, is to do the following:

  • Add a volume that will be persisted: ./keycloak-db:/opt/jboss/keycloak/standalone/data
  • Change the migration strategy from OVERWRITE_EXISTING, to IGNORE_EXISTING (in the command section)

In production, it is required by Keycloak that you use HTTPS. There are several ways to achieve this, including using a reverse proxy or load balancer that will manage HTTPS. We recommend that you read the Keycloak HTTPS documentation to learn more about this topic.

Okta

If you’d like to use Okta instead of Keycloak, it’s pretty quick using the Okta CLI. After you’ve installed it, run:

okta register

Then, in your JHipster app’s directory, run okta apps create and select JHipster. This will set up an Okta app for you, create ROLE_ADMIN and ROLE_USER groups, create a .okta.env file with your Okta settings, and configure a groups claim in your ID token.

Run source .okta.env and start your app with Maven or Gradle. You should be able to sign in with the credentials you registered with.

If you’re on Windows, you should install WSL so the source command will work.

If you’d like to configure things manually through the Okta developer console, see the instructions below.

First, you’ll need to create a free developer account at https://developer.okta.com/signup/. After doing so, you’ll get your own Okta domain, that has a name like https://dev-123456.okta.com.

Modify src/main/resources/config/application.yml to use your Okta settings. Hint: replace {yourOktaDomain} with your org’s name (e.g., dev-123456.okta.com).

security:
  oauth2:
    client:
      provider:
        oidc:
          issuer-uri: https://{yourOktaDomain}/oauth2/default
      registration:
        oidc:
          client-id: {client-id}
          client-secret: {client-secret}

Create an OIDC App in Okta to get a {client-id} and {client-secret}. To do this, log in to your Okta Developer account and navigate to Applications > Add Application. Click Web and click the Next button. Give the app a name you’ll remember, and specify http://localhost:8080/login/oauth2/code/oidc as a Login redirect URI. Click Done, then edit your app to add http://localhost:8080 as a Logout redirect URI. Copy the client ID and secret into your application.yml file.

Create a ROLE_ADMIN and ROLE_USER group (Users > Groups > Add Group) and add users to them. You can use the account you signed up with, or create a new user (Users > Add Person). Navigate to API > Authorization Servers, and click on the default server. Click the Claims tab and Add Claim. Name it groups, and include it in the ID Token. Set the value type to Groups and set the filter to be a Regex of .*. Click Create.

Add Claim

NOTE: If you want to use Okta all the time (instead of Keycloak), modify JHipster’s Protractor tests to use this account when running. Do this by changing the credentials in src/test/javascript/e2e/account/account.spec.ts and src/test/javascript/e2e/admin/administration.spec.ts.

After making these changes, you should be good to go! If you have any issues, please post them to Stack Overflow. Make sure to tag your question with “jhipster” and “okta”.

You can also use environment variables to override the defaults. For example:

export SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI="https://{yourOktaDomain}/oauth2/default"
export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID="{client-id}"
export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET="{client-secret}"

You can put this in an ~/.okta.env file and run source ~/.okta.env to override Keycloak with Okta.

You can then set these properties when you deploy to Heroku:

heroku config:set \
  SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI="$SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI" \
  SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID="$SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID" \
  SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET="$SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET"

For Cloud Foundry, you can use something like the following, where $appName is the name of your app.

export appName={your-app}
cf set-env $appName SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI "$SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI"
cf set-env $appName SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID "$SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID"
cf set-env $appName SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET "$SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET"

See Use OpenID Connect Support with JHipster to learn more about JHipster 5 and OIDC with Okta.

If you’re using JHipster 6, see Better, Faster, Lighter Java with Java 12 and JHipster 6. If you’re using microservices with JHipster 6, see Java Microservices with Spring Cloud Config and JHipster.

HTTPS

You can enforce the use of HTTPS when your app is running on Heroku by adding the following configuration to your SecurityConfiguration.java.

@Configuration
public class WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.requiresChannel()
      .requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
      .requiresSecure();
  }
}

This will work on both Heroku and Cloud Foundry. For more production tips on Heroku, see Preparing a Spring Boot App for Production on Heroku.

Leakage of implementation details

Every failure/exception is mapped to a problem datastructure and returned to the client.

{  
  "type": "https://www.jhipster.tech/problem/problem-with-message",
  "title": "Service Unavailable",
  "status": 503,
  "detail": "Database not reachable"
}

While JHipster does not include any stacktraces by default the detail contains the message of an exception which might reveal technical details you do not want to be exposed via the API.

{  
  "type": "https://www.jhipster.tech/problem/problem-with-message",
  "title": "Bad Request",
  "status": 400,
  "detail": "JSON parse error: Cannot deserialize instance of 
       `java.util.LinkedHashMap<java.lang.Object,java.lang.Object>` out of VALUE_NUMBER_INT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.LinkedHashMap<java.lang.Object,java.lang.Object>` 
       out of VALUE_NUMBER_INT token\n at [Source: (PushbackInputStream); line: 1, column: 1]"
}

To prevent this JHipster provides a dedicated mechanism to mitigate leakage of implementation details by

  • checking well known exception and replacing the message with a generic message (e.g. Unable to convert http message)
  • checking if the message contain potential package names (e.g. java. or .org) and replacing the message with a generic one (e.g. Unexpected runtime exception)

The logs still contain the detailed exception so you can still identify the real issue while an attacker from the outside is not able to gain valuable technical details by miusing your api.

In case you need to modify the logic (e.g. the message still contains technical details but was not detected) you can do so by adding the required logic to the prepare method in ExceptionTranslator.java