# Configuration

Out-of-the-box the SkillTree service (skills-service) comes packaged with smart defaults that are designed to work well for development and prototyping. In this section we'll discuss how to configure each distribution type followed by the catalog of available options.

There are two official types of distributions:

There are generally two types of configuration properties:

  • Application properties - passed to the application
  • JVM System properties - passed to JVM via -D or -X on the command line

TIP

Application properties conventions:

  • SkillTree specific properties start with a skills. prefix
  • Spring Boot specific properties start with a spring. prefix
    • skills-service is a Spring Boot application

Table of Contents:

# How to configure Jar-based install

Pass in Application properties at the end, each property should start with -- (double dash), for example:

java -jar ~/Downloads/skills-service-X.X.X.jar \
--spring.datasource.url=jdbc:postgresql://<host>:5432/skills \
--spring.datasource.username=<username> \
--spring.datasource.password=<pass>

Pass in JVM System properties before -jar, using -D or -X prefix, for example:

java -Xmx2G -Xms2G -jar ~/Downloads/skills-service-X.X.X.jar

# How to configure Docker-based install

The Docker-based install uses environment variables to configure Application and System properties:

  • SPRING_PROPS - Application properties
  • EXTRA_JAVA_OPTS - System properties

The following example configures Application properties

docker run --name skills-service -d -p 8080:8080 \
-e SPRING_PROPS="\
spring.datasource.url=jdbc:postgresql://<host>:5432/skills,\
spring.datasource.username=<username>,\
spring.datasource.password=<password>" \
skilltree/skills-service:<version>

TIP

Multiple properties are separated by a comma

This example configures both Application and System properties:

docker run --name skills-service -d -p 8080:8080 \
-e SPRING_PROPS="\
spring.datasource.url=jdbc:postgresql://<host>:5432/skills,\
spring.datasource.username=<username>,\
spring.datasource.password=<password>" \
-e EXTRA_JAVA_OPTS="-Xmx2G -Xms2G" \
skilltree/skills-service:<version>

# Configuration Properties Catalog

TIP

All of these properties are Application properties unless explicitly specified otherwise.

# Dashboard Project and Skill Definitions

Limit number of items that a Dashboard user can create:

# Maximum projects that a single user can be administrator for
skills.config.ui.maxProjectsPerAdmin=25
# Maximum number of subjects in a project
skills.config.ui.maxSubjectsPerProject=25
# Maximum number of badges in a project
skills.config.ui.maxBadgesPerProject=25
# Maximum number of skills in a project
skills.config.ui.maxSkillsPerSubject=100

When a project is first created it may not have enough total points to calculate a sensible levels breakdown.
Therefore, Skill Events cannot be applied until a minimum amount of points have been created for a project/subject as specified by these properties:

# Must create at least 100 points for project 
# before skill events are applied
skills.config.ui.minimumSubjectPoints=100
# Must create at least 100 points for each 
# subject before skill events are applied 
# for skills under this subject
skills.config.ui.minimumProjectPoints=100

Skill definition thresholds:

# Skill's Time Window threshold: Maximum number of minutes that can be assigned 
# to skill's Time Window property (default: 43,200 minutes = 30 days)
skills.config.ui.maxTimeWindowInMinutes=43200

# Maximum assignable skill version
skills.config.ui.maxSkillVersion=999
# maximum point increment for a skill
skills.config.ui.maxPointIncrement=10000
# maximum number of iterations required to complete a skill
skills.config.ui.maxNumPerformToCompletion=10000
# maximum number of occurrences within a time window
skills.config.ui.maxNumPointIncrementMaxOccurrences=999

# Dashboard: User Account Thresholds (Pass Auth Mode Only)

# Maximum number of characters for the first name 
skills.config.ui.maxFirstNameLength=30
# Maximum number of characters for the last name
skills.config.ui.maxLastNameLength=30
# Maximum number of characters for the primary name (aka nickname)
skills.config.ui.maxNicknameLength=70
# Minimum number of characters for the user name
skills.config.ui.minUsernameLength=5
# Minimum number of characters for the password
skills.config.ui.minPasswordLength=8
# Maximum number of characters for the password
skills.config.ui.maxPasswordLength=40

TIP

These attributes are not applicable to the PKI Mode and will be ignored if PKI Mode is enabled

Root URL of SkillTree documentation:

skills.config.ui.docsHost=https://code.nsa.gov/skills-docs

# SkillTree Support

You can display options for your users to reach out to the support team (ex. email, chat, ticketing center, etc).

Support options are displayed in the SkillTree Dashboard:

  • in the header under the Question Icon dropdown,
  • in the footer of the application.

More than one support option can be configured, here is a general template for configuring a support option:

skills.config.ui.supportLink<N>=<url>
skills.config.ui.supportLink<N>Label=<label>
skills.config.ui.supportLink<N>Icon=<font awesome free icon>

For example:

skills.config.ui.supportLink1=mailto:skilltreecoolsupport@someemailserver.com
skills.config.ui.supportLink1Label=Email Us
skills.config.ui.supportLink1Icon=fas fa-envelope-open-text

skills.config.ui.supportLink2=https://skilltreecoolestsupportcenter.com
skills.config.ui.supportLink2Label=Support Center
skills.config.ui.supportLink2Icon=fas fa-ambulance

Any Free Font Awesome Icons can be specified for the skills.config.ui.supportLink<N>Icon property.

# Dashboard: Input Validation

Here are some basic thresholds that are applied at the Dashboard UI and the backend:

# Maximum number of characters for a description (ex. Subject, Badge, Skill, etc..)
skills.config.ui.descriptionMaxLength=2000

# Minimum number of characters for the name (ex. Subject, Badge, Skill, etc..) 
skills.config.ui.minNameLength=3
# Maximum number of characters for Badge's name
skills.config.ui.maxBadgeNameLength=50
# Maximum number of characters for Project's name
skills.config.ui.maxProjectNameLength=50
# Maximum number of characters for Skill's name
skills.config.ui.maxSkillNameLength=100
# Maximum number of characters for Subject's name
skills.config.ui.maxSubjectNameLength=50
# Maximum number of characters for Level's name
skills.config.ui.maxLevelNameLength=50
# Minimum number of characters for id (ex. Subject, Badge, Skill, etc..)
skills.config.ui.minIdLength=3
# Maximum number of characters for id (ex. Subject, Badge, Skill, etc..)
skills.config.ui.maxIdLength=50

Regex based validation for Name and Description (this validation is not enabled by default):

# Regular expression that each paragraph in the description must comply with
skills.config.ui.paragraphValidationRegex=
# Message to display if regex validation fails
skills.config.ui.paragraphValidationMessage=

# Regular expression that a name (ex. Subject, Badge, Skill, etc..) must comply with
skills.config.ui.nameValidationRegex=
# Message to display if regex validation fails
skills.config.ui.nameValidationMessage=

# Latency Profiling

skills-service comes with built-in latency profiling of its endpoints, to enable:

# Enable profiling
skills.prof.enabled=true
# Profiling is only generated if endpoint's performance exceeds this number of milliseconds
skills.prof.minMillisToPrint=500

When enabled and an overall endpoint execution time exceeds skills.prof.minMillisToPrint then the detailed call stack profiling is printed to the log.

Profiling statement will look something like this:

Profiling Endpoint: /admin/projects/Project1/users
|-> getProjectUsers(projectId=Project1,query=,limit=5,page=1,orderBy=lastUpdated,ascending=false) (1) : 815ms [017ms]
|     |-> AdminUsersService.findDistinctUsers (1) : 672ms
|     |-> AdminUsersService.countTotalProjUsers (3) : 126ms

The output provides method call hierarchy as well as the following information:

  • Total method execution time: number in ms, seconds and/or minutes
  • (N): number of times method was called, findDistinctUsers() was called once and countTotalProjUsers() called 3 times
  • [N ms]: execution time which was not accounted for by child methods/logic; this happens when either not all of the child methods/logic is profiled OR there is GC or JVM overhead

SkillTree profiling uses the Call Stack Profiler library

skills-service also supports the Server Timing API and when enabled will set server timing data in the response header. Most browsers visualize this timing data in their respective development tools. To enable, please set the following property:

skills.prof.serverTimingAPI.enabled=true

In Chrome for example, open the development tools and navigate to the Network tab. Click on the skills-service endpoint and then click on the Timing Tab. On the bottom you will see Server Timing section which will contain overall endpoint execution time (from the server's point of view) and associated profiling id that will allow you to locate the associated profiling statement in the logs.

For example, the name in the Chrome development tools will look something like this profId1642707755421 (profId<id>). To locate the associated profiling statement you can search for the profId=1642707755421 (profId=<id>):

Profiling Endpoint: /admin/projects/Project1/users
|-> getProjectUsers(projectId=Project1,query=,limit=5,page=1,orderBy=lastUpdated,ascending=false) profId=1642707755421 (1) : 815ms [017ms]
|     |-> AdminUsersService.findDistinctUsers (1) : 672ms
|     |-> AdminUsersService.countTotalProjUsers (1) : 126ms

Please note

  • In order for the Server Timing API to work skills.prof.enabled must be set to true
  • Profiling statements are only printed to the log if an overall endpoint execution time exceeds skills.prof.minMillisToPrint

Endpoint profiling printing threshold can be further customized / overridden per endpoint:

# You will need to know the name of the method to customize 
skills.prof.endpoints.<endpoint-method-name>=1000

There are also configuration options to tweak profiling of the asynchronous jobs. Please note that the profiling of asynchronous jobs is always enabled.

# Async Job: Changes to the original skill (ex. description, occurrences) are automatically 
# synchronized to all the imported skills as well. Default is 2000
skills.async.syncCatalogSkillDefinition.prof.minMillisToPrint=2000

# Async Job: As skill occurrences are reported to the original project they are 
#also automatically propagated to the imported skills within other projects. Default is 500
skills.async.reportSkill.prof.minMillisToPrint=500

# Database

Configure DB:

spring.datasource.url=
spring.datasource.username=
spring.datasource.password=

# WebSocket Stomp Broker

Configure external WebSocket Stomp Broker:

skills.websocket.enableStompBrokerRelay=true
skills.websocket.relayHost=
skills.websocket.relayPort=

# JVM Heap

These are System Properties.

-Xms2g -Xmx2g

# GC Logging

These are System Properties.

-Xlog:gc=debug:file=./gc.log:time,uptime,level,tags:filecount=5,filesize=100m

TIP

Generally gc logging is only enabled in development deployments.

# HttpStore

When deploying more than 1 instance of skills-service HttpSession must be persisted centrally. SkillTree supports storing HttpSession in Postgres via JDBC or in Redis.

Option 1: HttpStore persisted in PostgreSQL (Recommended)

spring.session.store-type=jdbc
spring.session.jdbc.initialize-schema=always

# Optional: can specify duration suffix but if omitted then it defaults to seconds
server.servlet.session.timeout= 

Option 2: HttpStore persisted in Redis

spring.session.store-type=redis
spring.data.redis.host=localhost
spring.data.redis.password=
spring.data.redis.port=6379 

# Optional: Flush mode
spring.session.redis.flush-mode=on_save 
# Optional: Stores session namespace to use for the keys
spring.session.redis.namespace=spring:session 
# Optional: can specify duration suffix but if omitted then it defaults to seconds
server.servlet.session.timeout= 

# https SSL (Pass Auth Mode Only)

Configure https:

server.port=8443
server.ssl.enabled=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=/path/to/keystore.p12
server.ssl.key-store-password=

# Force TLSv1.2 until https://bugs.openjdk.java.net/browse/JDK-8241248 is fixed
server.ssl.enabled-protocols=TLSv1.2

# Email Verification (Pass Auth Mode Only)

You can enable verification of the email ownership when dashboard accounts are created by setting the following property:

skills.authorization.verifyEmailAddresses=true

When a new account is created that user will be sent a verification email. The user will have to click on the verification link in the email prior their login credentials can be used.

# 2-way SSL (PKI Mode Only)

Configure https and 2-way SSL:

server.port=8443
server.ssl.enabled=true
server.ssl.client-auth=want
	
# Force TLSv1.2 until https://bugs.openjdk.java.net/browse/JDK-8241248 is fixed
server.ssl.enabled-protocols=TLSv1.2

# keystore
server.ssl.key-store=/certs/keystore.p12
server.ssl.key-store-password=
server.ssl.keyStoreType=PKCS12

# truststore
server.ssl.trust-store=/certs/truststore.p12
server.ssl.trust-store-password=
server.ssl.trustStoreType=PKCS12

# User Info Service (PKI Mode Only)

User Info Service client properties:

# To retrieve user info by DN
skills.authorization.userInfoUri=https://<host>:<port>/userInfo?dn={dn}
# Used by dashboard dropdowns to suggest existing users
skills.authorization.userQueryUri=https://<host>:<port>/userQuery?query={query}
# skills-service checks the health of User Info Service
skills.authorization.userInfoHealthCheckUri=https://<host>:<port>/actuator/health

If User Info Service utilizes 2-way SSL then add the following client authentication properties (Java System Properties):

# Keystore
-Djavax.net.ssl.keyStore=/certs/keystore.p12
-Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.keyStorePassword=

# Truststore
-Djavax.net.ssl.trustStore=/certs/truststore.p12
-Djavax.net.ssl.trustStoreType=PKCS12
-Djavax.net.ssl.trustStorePassword=

If you are running with self-signed certs you can optionally disable host verification (development only):

skills.disableHostnameVerifier=false

# OAuth Support (Pass Auth Mode Only)

When using Password Auth Mode, the dashboard can also support OAuth2 based authentication. Currently, OAuth2 is only supported for Google, GitHub, GitLab and Azure Active Directory.
Login buttons get automatically added to the Login page when configured.
To configure, you will need a client ID and client Secret credentials.
These credentials can be created and managed through the providers OAuth Google , GitHub , GitLab , or Azure AD management pages.

Once the client ID and secret are set up, they are enabled by adding the following properties:

# Google
spring.security.oauth2.client.registration.google.client-id=<Google client id here>
spring.security.oauth2.client.registration.google.client-secret=<Google client secret here>
spring.security.oauth2.client.registration.google.redirectUriTemplate='https://<SkillTree Dashboard Host>/{action}/oauth2/code/{registrationId}'
spring.security.oauth2.client.registration.google.iconClass=fab fa-google

# GitHub
spring.security.oauth2.client.registration.github.client-id=<GitHub client id here>
spring.security.oauth2.client.registration.github.client-secret=<GitHub client secret here>
spring.security.oauth2.client.registration.github.redirectUriTemplate='https://<SkillTree Dashboard Host>/{action}/oauth2/code/{registrationId}'
spring.security.oauth2.client.registration.github.iconClass=fab fa-github

# GitLab
spring.security.oauth2.client.registration.gitlab.client-id=<GitLab client id here>
spring.security.oauth2.client.registration.gitlab.client-secret=<GitLab  client secret here>
spring.security.oauth2.client.registration.gitlab.redirect-uri=https://<SkillTree Dashboard URL>/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.gitlab.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.gitlab.clientName=GitLab
spring.security.oauth2.client.registration.gitlab.iconClass=fab fa-gitlab
spring.security.oauth2.client.provider.gitlab.authorization-uri=https://gitlab.com/oauth/authorize
spring.security.oauth2.client.provider.gitlab.token-uri=https://gitlab.com/oauth/token
spring.security.oauth2.client.provider.gitlab.user-info-uri=https://gitlab.com/api/v4/user
spring.security.oauth2.client.provider.gitlab.user-name-attribute=username

# Azure AD
spring.security.oauth2.client.registration.azure.client-id=<Azure App Registration client ID>
spring.security.oauth2.client.registration.azure.client-secret=<Azure App Registration client secret>
spring.security.oauth2.client.registration.azure.redirect-uri=https://<SkillTree Dashboard URL>/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.azure.iconClass=fab fa-microsoft
spring.security.oauth2.client.registration.azure.scope=openid,profile,email
spring.security.oauth2.client.registration.azure.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.azure.client-name=Azure
spring.security.oauth2.client.registration.azure.provider=azuread
spring.security.oauth2.client.provider.azuread.authorization-uri=https://login.microsoftonline.com/common/oauth2/v2.0/authorize
spring.security.oauth2.client.provider.azuread.token-uri=https://login.microsoftonline.com/common/oauth2/v2.0/token
spring.security.oauth2.client.provider.azuread.user-info-uri=https://graph.microsoft.com/oidc/userinfo
spring.security.oauth2.client.provider.azuread.jwk-set-uri=https://login.microsoftonline.com/common/discovery/keys

Excluding a provider configuration section will prevent the respective OAuth login button from being added to the Login page.

Note: To disable username/password authentication entirely and only support OAuth based authentication, set the following configuration property:

skills.authorization.oAuthOnly=true

# Progress and Ranking Views

A single point of access for training profiles available to the user as well as user's current progress and ranking. The Progress and Ranking views give a user access to the Skills Display for all projects which have elected to set its Project Discoverability setting to Add to Project Catalog on that instance of the SkillTree platform. It provides a single point of access for training profiles available to the user as well as a mechanism for Projects that consist entirely of self-reported Skills to provide access to the Ranking and Progress display for their users.

Progress and Ranking Views are disabled by default, but can be easily enabled:

# enable Progress and Ranking Views
skills.config.ui.rankingAndProgressViewsEnabled=true

# optionally change default for the landing page (admin is the default)
skills.config.ui.defaultLandingPage=progress

# Upgrade-In-Progress State

In order to safely upgrade the database engine, SkillTree can be easily transitioned to a Upgrade-In-Progress state. When that happens:

  • the SkillTree Dashboard is placed into a read-only state: dashboard can be viewed and navigated but mutations will not be allowed
  • skill requests are retained in a Write-Ahead-Log (WAL) to be replayed after the upgrade is done

Please configure the following properties in order to place skills-service in the Upgrade-In-Progress state:

# place the SkillTree platform in the Upgrade-In-Progress state 
skills.config.db-upgrade-in-progress=true
# specify the location of the directory where the Write-Ahead-Logs will be stored   
skills.queued-event-path=/queued_events

When the SkillTree Dashboard is started with the skills.config.db-upgrade-in-progress property set to true it will:

  • display a prominent banner on the top of the SkillTree Dashboard and any embedded Skills Display informing users that an upgrade is in progress
  • any mutation (ex. creating/editing skills/projects/badges, etc...) will redirect users to an informational page indicating that an upgrade is in progress
  • skill requests are accepted and stored in the WAL in the directory specified by the skills.queued-event-path property

General steps to upgrade the database engine:

  1. start the new database on a different instance/node
  2. transition SkillTree production instance to the Upgrade-In-Progress state
  3. export data from the current production database instance
  4. import data into the new database instance
  5. reconfigure SkillTree production instance to point to the new database and turn off the Upgrade-In-Progress state
    • when the skills-service is restarted it will replay the events stored in the WAL; the WAL files will then be removed

# Private Invite Only Projects

In the case of Private Invite Only Projects, users are invited to join a project. Invited recipients are emailed a one-time invite code and by default that invite code can be used by any valid user.

When skills.authorization.invite.validateEmail is set to true, the invite code is compared to the user's email address prior giving access to that private project.

# when enabled, only users whose email addresses matche the one assigned to the invite token will be given access 
skills.authorization.invite.validateEmail=true

# Spring Boot Properties

skills-service is a Spring Boot application and will respect the majority (if not all) of Spring Boot configuration properties.
Here is the complete list of available Spring Boot Properties

Last Updated: 11/3/2023, 11:47:32 AM