Configuration

Plug-Front

The only local configuration needed at Plug-Front is how to initially connect to one of the backends with failover to the next on the list. Plug-Front retrieves needed configuration from backend during start-up and will be automatically updated if configuration at backend later on changes. After successfully downloading configuration, base_urls defined in local configuration file will be updated according to the backend settings (all backend servers defined will automatically be included in base_urls). A version number will also be included and corresponds with version defined at backend. By looking at version number defined at Plug-Front and Plug-Back, we can verify that configuration is synchronized.

Configuration file <plug-front>/config/config.yml example:

plugfront:
  backend:
    base_urls:
    - https://<plug-back-one>:9091
    - https://<plug-back-two>:9091
    password: password
    username: plugadm

Plug-Front initial configuration

Plug-Front retrieve full configuration from Plug-Back. Following initial configuration is needed on Plug-Front for establishing connection to Plug-Back:

Config key Description
plugfront.backend.base_urls Syntax https://<plug-back-hostname>:<port>. Port must correspond with Plug-Back port configuration. Contains one or more backend servers to be contacted for downloading needed configuration. On startup there must be at least one base_urls defined. After successfully download and configuration, base_urls list will become updated according to the configuration defined by backend, and base_urls should then contain a list of all backend servers. plugfront.backend.version will also be updated and corresponds with version defind at backend. There is built-in logic for load balancing and failover
plugfront.backend.password Clear text password will become encrypted on start-up and must correspond with password defined at plug-back
plugfront.backend.username Username must corresponding with username defined at plug-back
plugfront.loglevel error, info or debug - optional and if defined it will override corresponding configuration retrieved from plug-back
plugfront.log_to_console true or false - optional and if defined it will override corresponding configuration retrieved from plug-back

Using environments

Configuration may also be set by environments.

Syntax is variable names like above dotted notation, but starting with PLUGSSO_, all uppercase, and underscore instead of dots. Example (linux using “export”, windows using “set”):

export PLUGSSO_PLUGFRONT_BACKEND_USERNAME=plugadm
export PLUGSSO_PLUGFRONT_BACKEND_PASSWORD=password
export PLUGSSO_PLUGFRONT_BACKEND_BASEURLS=https://192.168.253.1:9091

Environments may also be defined in a vault file having only the initial vaultfile defined as environment

Example:

export PLUGSSO_VAULTFILE=./config/.vaultfile

file "./config/.vaultfile" content:
PLUGSSO_PLUGFRONT_BACKEND_USERNAME=plugadm
PLUGSSO_PLUGFRONT_BACKEND_PASSWORD=password
PLUGSSO_PLUGFRONT_BACKEND_BASEURLS=https://192.168.253.1:9091,https://192.168.253.20:9091

Plug-Back

Plug-Back is the backend component having PlugSSO configuration that covers both Plug-Back and Plug-Front. All backend nodes should be included in plugback.cluster_nodes. We should also include a increasing version number. Configuration will be automatically synchronized among all cluster_nodes defined and connected frontends.

Note, when configuration have been changed at a specific Plug-Back node, this node also have to be restarted to have the new configuration activated. The new configuration version will then be automatically synchronized among all Plug-Back and Plug-Front nodes.

Configuration file <plug-back>/config/config.yml have following main components:

domains:
- domain_name: Domain1
  authentications:
  - endpoint_name: Google
    pre_login:
      background_image: ./static/img/logo-google.png
      display_name: Login with Google
      url_path: /sso/app1
  authz_endpoint_name: AD
  realms:
  - /app1
  - /app2
  use_authz: true
  use_mfa:
    method: otp
    selections:
    - OTP,otp
    - U2F/FIDO2,u2f
    - U2F/FIDO2 (less),u2f-username-less
  use_pre_login: true
endpoint:
  oauth:
  - config:
      endpoint_name: Google
      ...
  directory:
  - config:
      endpoint_name: AD
      ...
  scimgateway:
  - config:
      endpoint_name: my-scimgateway
      ...
  local:
  - config:
      endpoint_name: local-allowlist
      allowlist_users:
      ...
plugback:
  cluster_nodes:
  - plug-back-one.mycompany.com
  - plug-back-two.mycompany.com
  ...
plugfront:
  ...
version: 1.0

Endpoint section contains endpoint configuration used for authentication and authorization. There are three types of endpoints: oauth, directory, scimgateway and local. We can define as many as we want, and they must have a unique endpoint_name. This endpoint_name will then be used in the domain section for referring to the specific endpoint.

Domains contains one or more domain having the main SSO configuration. For each domain we have to configure:

  • One or more authentications using endpoint_name for referring to the actual authentication endpoint. When having several authentications defined, we also need use_pre_login = true, else the first authentication defined will be used without any pre-login dialog.
  • If using authorization (use_authz = true), authz_endpoint_name must be set to a valid endpoint_name defined in the endpoint section
  • realms contains a list of valid url paths that can be accessed, and any sub paths will automatically be included. Accessing a url having a path not defined in realms will be denied.
  • use_mfa includes a method and optional selections. method = null, otp, u2f or u2f-username-less which sets default mfa method. If selection is defined, prelogin will present selections in a drop-down listbox as available mfa authentication methods.
  • use_authz = true, activates authorization
  • use_pre_login = true, enables prelogin dialog for selecting where to login. Dialog box will be built dynamically based on what is defined the authentication section and will show background_image and display_name for each option.

Having several domains is useful when we need different types of configuration. For example we have an admin url that only administrators are allowed to access. We could then define a new domain having a realm that includes this url and specify a new authz_endpoint_name that is configured for only allowing administrators e.g. only allowing users having AD group membership = xxx.

Notes regarding domains:

  • There are no Single-Sign On between domains. Accessing a realm (url) in Domain1 and then accessing a realm in Domain2, requires a new authentication/authorization for Domain2.
  • A realm belongs to one domain. This means, we can’t define the same realm (or sub-paths) in other domains
  • realm path will automatically include sub-paths e.g.:
    • /app3/abc also includes all sub-paths below “abc” like /app3/abc/123
    • / includes everything and will override all other realms defined

plugback section contains misc. Plug-Back related configuration
plugfront section contains misc. Plug-Front related configuration

version is numeric value for this configuration file version (e.g. 1.1 and 2). Note, modifying configuration file and restarting plug-back will automatically update all other plug-back and plug-front servers with the new configuration. We should therefore always increment the version when modifying configuration file. We can then on each plug-back/plug-front see if configuration file versions are in sync. Note, lowering the version number will automatically be reverted back to the highest version number by peer backend servers. If version is not included, it will default to 0.

Configuration example 1

  • One domain
  • Direct Azure tenant login (no prelogin dialog box for selecting where to login)
  • No authorization
  • Using OTP multifactor authentication
  • Having three plug-back servers
domains:
- authentications:
  - endpoint_name: AzureMyCompany
  authz_endpoint_name: null
  domain_name: Domain1
  realms:
  - /app1
  - /app2
  use_authz: false
  use_mfa:
    method: otp
    selections: null
  use_pre_login: false
endpoint:
  oauth:
  - config:
      endpoint_name: AzureMyCompany
      callback_url: https://<plugsso.mycompany.com>/plug/auth
      client_id: azure-application-client-id
      client_secret: azure-application-client-secret
      provider: azure
      tenant: AzureAdMyOrg
plugback:
  certificate:
    certfile: plug-back.cert
    keyfile: plug-back.key
  cluster_nodes:
  - plug-back-one.mycompany.com
  - plug-back-two.mycompany.com
  - plug-back-three.mycompany.com
  listen: 0.0.0.0
  log_to_console: false
  loglevel: error
  password: password
  port: 9091
  username: plugadm
plugfront:
  allowlist_domains:
  allowlist_geo_locations:
  allowlist_users:
  cookie:
    httponly: true
    maxage: 0
    samesite_mode: none
    secure: true
  displayname: PlugSSO
  headers:
  jwt:
    maxage: 240
  log_to_console: false
  loglevel: error
  oidc_provider:
  smtp:
    host: smtp.mycompany.com
    proxy:
    password: password
    port: 587
    username: [email protected]
version: 1.1

Configuration example 2

Same as example 1, but includes:

  • using prelogin: Azure, Google and local AD login
  • using built-in directory authorization (not through SCIM Gateway). Also verify that user exist in Active Directory as a normal account, is enabled and password not expired
  • claims attributes will become header variables included in the destination communication.
domains:
- authentications:
  - endpoint_name: AzureMyCompany
    pre_login:
      background_image: ./static/img/logo-mycompany.png
      display_name: Login with MyCompany
      url_path: /app1
  - endpoint_name: Google
    pre_login:
      background_image: ./static/img/logo-google.png
      display_name: Login with Google
      url_path: /app1
  - endpoint_name: AD
    pre_login:
      url_path: /app2
  authz_endpoint_name: AD
  domain_name: Domain1
  realms:
  - /app1
  - /app2
  use_authz: true
  use_mfa:
    method: otp
    selections: null
  use_pre_login: true
endpoint:
  oauth:
  - config:
      endpoint_name: AzureMyCompany
      callback_url: https://<plugsso.mycompany.com>/plug/auth
      client_id: azure-application-client-id
      client_secret: azure-application-client-secret
      provider: azure
      tenant: AzureAdMyOrg
  - config:
      endpoint_name: Google
      auth_url: https://accounts.google.com/o/oauth2/auth
      callback_url: https://<plugsso.mycompany.com>/plug/auth
      client_id: google-client-id
      client_secret: google-client-secret
      preferreddomain: gmail.com
      provider: google
  directory:
  - config:
      endpoint_name: AD
      base_dn: CN=Users,DC=mycompany,DC=com
      mail_attr: mail
      search_filter: (&(objectClass=person)(|(sAMAccountName={username})(mail={username}))(|(useraccountcontrol=512)(useraccountcontrol=66048)))
      urls:
      - ldaps://<ad-domain-controller-one>:636
      - ldaps://<ad-domain-controller-two>:636
      user_dn: CN=plugsso,CN=Users,DC=mycompany,DC=com
      user_password: password
plugback:
  certificate:
    certfile: plug-back.cert
    keyfile: plug-back.key
  cluster_nodes:
  - plug-back-one.mycompany.com
  - plug-back-two.mycompany.com
  - plug-back-three.mycompany.com
  listen: 0.0.0.0
  log_to_console: false
  loglevel: error
  password: password
  port: 9091
  username: plugadm
plugfront:
  allowlist_domains:
  allowlist_geo_locations:
  allowlist_users:
  cookie:
    httponly: true
    maxage: 0
    samesite_mode: none
    secure: true
  displayname: PlugSSO
  headers:
    claims:
    - sAMAccountName
    - given_name
  jwt:
    maxage: 240
  log_to_console: false
  loglevel: error
  oidc_provider:
  smtp:
    host: smtp.mycompany.com
    proxy:
    password: password
    port: 587
    username: [email protected]
version: 1.2

Configuration example 3

Same as example 2, but includes:

  • Two domains
  • Domain1 having multifactor prelogin selections (named as: OTP, U2F/FIDO2 and U2F/FIDO2 (less))
  • Domain2 using same Azure tenant login as Domain1, and includes local login through SCIM Gateway
  • Domain2 using Authorization through SCIM Gateway
domains:
- authentications:
  - endpoint_name: AzureMyCompany
    pre_login:
      background_image: ./static/img/logo-mycompany.png
      display_name: Login with MyCompany
      url_path: /sso/app1
  - endpoint_name: Google
    pre_login:
      background_image: ./static/img/logo-google.png
      display_name: Login with Google
      url_path: /sso/app1
  - endpoint_name: AD
    pre_login:
      url_path: /sso/app2
  authz_endpoint_name: AD
  domain_name: Domain1
  realms:
  - /app1
  - /app2
  use_mfa:
    method: otp
    selections:
    - OTP,otp
    - U2F/FIDO2,u2f
    - U2F/FIDO2 (less),u2f-username-less
  use_pre_login: true
- authentications:
  - endpoint_name: AzureMyCompany
    pre_login:
      background_image: ./static/img/logo-mycompany.png
      display_name: Login with MyCompany
      url_path: /app3
  - endpoint_name: plug-scimgateway
    pre_login:
      display_name: Internal login
      url_path: /app3
  authz_endpoint_name: plug-scimgateway
  domain_name: Domain2
  realms:
  - /app3
  - /app4
  use_mfa:
    method: otp
    selections: null
  use_pre_login: true
endpoint:
  oauth:
  - config:
      endpoint_name: AzureMyCompany
      callback_url: https://<plugsso.mycompany.com>/plug/auth
      client_id: azure-application-client-id
      client_secret: azure-application-client-secret
      provider: azure
      tenant: AzureAdMyOrg
  - config:
      endpoint_name: Google
      auth_url: https://accounts.google.com/o/oauth2/auth
      callback_url: https://<plugsso.mycompany.com>/plug/auth
      client_id: google-client-id
      client_secret: google-client-secret
      preferreddomain: gmail.com
      provider: google
  directory:
  - config:
      endpoint_name: AD
      base_dn: CN=Users,DC=mycompany,DC=com
      mail_attr: mail
      search_filter: (&(objectClass=person)(|(sAMAccountName={username})(mail={username}))(|(useraccountcontrol=512)(useraccountcontrol=66048)))
      urls:
      - ldaps://<ad-domain-controller-one>:636
      - ldaps://<ad-domain-controller-two>:636
      user_dn: CN=plugsso,CN=Users,DC=mycompany,DC=com
      user_password: password
  scimgateway:
  - config:
      endpoint_name: plug-scimgateway
      method: post
      password: password
      path: /plugsso/api
      urls:
      - http://<scimgateway-host1>:8890
      - http://<scimgateway-host2>:8890
      user: gwadmin
plugback:
  certificate:
    certfile: plug-back.cert
    keyfile: plug-back.key
  cluster_nodes:
  - plug-back-one.mycompany.com
  - plug-back-two.mycompany.com
  - plug-back-three.mycompany.com
  listen: 0.0.0.0
  log_to_console: false
  loglevel: error
  password: password
  port: 9091
  username: plugadm
plugfront:
  allowlist_domains:
  allowlist_geo_locations:
  allowlist_users:
  cookie:
    httponly: true
    maxage: 0
    samesite_mode: none
    secure: true
  displayname: PlugSSO
  headers:
    claims:
    - sAMAccountName
    - given_name
  jwt:
    maxage: 240
  log_to_console: false
  loglevel: error
  oidc_provider:
  smtp:
    host: smtp.mycompany.com
    proxy:
    password: password
    port: 587
    username: [email protected]
version: 1.3

Configuration example 4

Example showing the use of built-in OpenID Connect provider:

  • One domain
  • General Oauth OIDC login (previous examples showed simplified Azure and Google)
  • Local login using SCIM Gateway
  • Authorization through SCIM Gateway
  • Using multifactor authentication
  • Having three plug-back servers
  • Built-in OpenID Provider, see section oidc_provider. Also note that we need the callback url that is used by the remote client to be included in the realm definition. This is to allow PlugSSO authentication if not already authenticated.
domains:
- authentications:
  - endpoint_name: SomeOidcProvider
    pre_login:
      background_image: ./static/img/logo-mycompany.png
      display_name: Login with MyCompany
      url_path: /app1
  - endpoint_name: plug-scimgateway
    pre_login:
      display_name: Internal login
      url_path: /app1
  authz_endpoint_name: plug-scimgateway
  domain_name: Domain1
  realms:
  - /app1
  - /app2
  - /auth/system1/callback
  - /auth/system2/callback
  use_mfa:
    method: otp
    selections: null
  use_pre_login: true
endpoint:
  oauth:
  - config:
      endpoint_name: SomeOidcProvider
      provider: oidc
      auth_url: https://<host/oauth2/v1/authorize>.
      callback_url: https://<plug-front-hostname>/plug/auth
      client_id: <client-id>.
      client_secret: <client-secret>.
      scopes:
      - openid
      - email
      - profile
      token_url: https://<host/oauth2/v1/token>.
      user_info_url: https://<host/oauth2/v1/userinfo>.
  scimgateway:
  - config:
      endpoint_name: plug-scimgateway
      method: post
      password: password
      path: /plugsso/api
      urls:
      - http://<scimgateway-host1>:8890
      - http://<scimgateway-host2>:8890
      user: gwadmin
plugback:
  certificate:
    certfile: plug-back.cert
    keyfile: plug-back.key
  cluster_nodes:
  - plug-back-one.mycompany.com
  - plug-back-two.mycompany.com
  - plug-back-three.mycompany.com
  listen: 0.0.0.0
  log_to_console: false
  loglevel: error
  password: password
  port: 9091
  username: plugadm
plugfront:
  allowlist_domains:
  allowlist_geo_locations:
  allowlist_users:
  cookie:
    httponly: true
    maxage: 0
    samesite_mode: none
    secure: true
  displayname: PlugSSO
  headers:
    claims:
    - scim_groups
  jwt:
    maxage: 240
  log_to_console: false
  loglevel: error
  oidc_provider:
    oidc_configs:
    - callback_url: https://<company1.com/auth/system1/callback>.
      client_id: this_is_client_id1
      client_secret: this_is_client_secret1
    - callback_url: https://<company2.com/auth/system2/callback>.
      client_id: this_is_client_id2
      client_secret: this_is_client_secret2
    signing_certificate:
      certfile: ecdsa.cert
      keyfile: ecdsa.key
  smtp:
    host: smtp.mycompany.com
    proxy:
    password: password
    port: 587
    username: [email protected]
version: 1.4

Plug-Back configuration options

plug-back configuration also includes plug-front. plug-front retrieves this configuration from plug-back.

Config key Description
domains contains one or more domain having the main SSO configuration
domains.domain_name uniqe name of the domain
domains.authentications contains one or more authentication options to be used
domains.authentications.endpoint_name referres to the endpoint_name defined in endpoint section that will be used by the authentication process
domains.authentications.pre_login pre-login dialog box configuration
domains.authentications.pre_login.background_image image file to be displayed
domains.authentications.pre_login.display_name name to be displayed with the image file
domains.authentications.pre_login.url_path where to send user after successful login in case user do access the prelogin page directly (plug/prelogin). Value must be a valid realm in current domain
domains.authz_endpoint_name referres to the endpoint_name defined in endpoint section that will be used by the authorization process
domains.realms realms contains a list of valid url paths that can be accessed, also automatically including sub paths. Accessing a url having a path not defined in realms will be denied
domains.mfa multifactor authentication configuration
domains.mfa.method null, otp, u2f or u2f-username-less sets default mfa method (null means mfa not in use). otp is one-time-password using authenticator app. u2f is universal 2nd factor FIDO2/WebAuthn. u2f-username-less is u2f in both password-less and username-less mode.
domains.mfa.selections array of <selecion name>,<method>. If defined, prelogin wil have a drop-down selection box letting user select which mfa to be used. <slection name> is what user will see, and <method> is the method to be used and must be one of the supported mfa.methods
domains.use_authz true or false. true, activates authorization
domains.use_pre_login true or false. true, enables prelogin dialog for selecting where to login. Dialog box will be built dynamically based on what is defined in the authentication section and will show background_image and display_name for each option. Internal logon having user input fields for username/password will be shown for none oauth endpoint e.g. type endpoint.directory and endpoint.scimgateway (only one internal logon is supported)
endpoint contains needed endpoint configuration used for authentication and authorization. There are three types of endpoints: oauth, directory and scimgateway. We can define as many as we want, and they must have a unique endpoint_name. This endpoint_name will then be used in the domain section for referring to a specific endpoint
endpoint.oauth contains one or more oauth endpoint configuration
endpoint.oauth.config configuration section
endpoint.oauth.config.provider oicd, azure, google or github. oidc is the general OpenID Connect configuration while azure and google are built-in having simplified configuration
endpoint.oauth.config.xxx for oidc, azure, google and github provider configuration, see dedicated chapter in this document
endpoint.directory contains one or more directory endpoint configuration
endpoint.directory.config configuration section
endpoint.directory.config.endpoint_name unique endpoint name
endpoint.directory.config.base_dn where to start ldap search
endpoint.directory.config.mail_attr attribute containing users mail address. If no mail-address and using directory for authentication, user will be forced to enter a mail-address during the OTP registration process (because of self-service recovery code)
endpoint.directory.config.search_filter search filter that should return one user only. If using authorization, filter should also include needed authorization logic. PlugSSO will replace {username} with user login name, normally this would be mail-address or it could be UserId when using local login e.g.
(&(objectClass=person)(|(sAMAccountName={username})(mail={username}))(|(useraccountcontrol=512)(useraccountcontrol=66048)))
endpoint.directory.config.urls one or more ldap/ldaps connection urls. When more than one is defined, there will be failover logic in the sequence defined.
endpoint.directory.config.user_dn user dn having directory read access to all users
endpoint.directory.config.user_password directory user password. Clear text password that will become encrypted on start-up
endpoint.scimgateway contains one or more scimgateway endpoint configuration
endpoint.scimgateway.config configuartion section
endpoint.scimgateway.config.endpoint_name unique endpoint name
endpoint.scimgateway.config.method get or post. Must correspond with custom SCIM Gateway plugin. Plug SSO will always send a body containing known user attributes. If password attribute is included, it means plugin also have to authenticate user including any authorization
endpoint.scimgateway.config.path SCIM Gateway url path e.g. /api or using baseEntity /plugsso/api. Must correspond with custom SCIM Gateway plugin
endpoint.scimgateway.config.urls SCIM Gateway base url. When more than one is defined, there will be failover logic in the sequence defined
endpoint.scimgateway.config.user SCIM Gateway admin user
endpoint.scimgateway.config.password SCIM Gateway admin user password. Clear text password will become encrypted on start-up
endpoint.local contains one or more local configuration used for authorizing users based on allowlist_users settings, not used for authentication
endpoint.local.config configuartion section
endpoint.local.config.endpoint_name unique endpoint name
endpoint.local.config.allowlist_users array of one or more username that are authorized
plugback backend configuration: plug-back (current server)
plugback.certificate certificate configuration for tls communication. Note, certificate will be autogenerated if not defined
plugback.certificate.certfile certificate file name. File must be located in <plug-back/config/certs
plugback.certificate.keyfile certificate private key file name. File must be located in <plug-back/config/certs
plugback.cluster_nodes a list of all plug-back servers (FQDN) that will be in sync and also used by plug-front
plugback.listen listen port, Plug-Front communicates with Plug-Back using this port
plugback.log_to_console true or false. true or false. When true, logging to console instead of file, and we can use stdout/stderr redirect if needed
plugback.loglevel error, info or debug. Logs to <plug-back>/logs/plug-front.log having file rollover at 10 MB and keeping 10 files
plugback.password clear text password will become encrypted (note, corresponding plugfront.backend.password)
plugback.port default 9091, plug-front communicates with plug-back using this port (note, corresponding port in plugfront.backend.base_urls)
plugback.port_cluster_sync default plugback.port + 1 (9092), port number for cluster synchronization between plug-back servers
plugback.username user name (note, corresponding plugfront.backend.username)
plugfront frontend configuration: Plug-Front
plugfront.allowlistdomains one or more mail-domains. If defined, users having mail-address with a domain that is not included in this list will be denied access e.g: MyCompany.com will only allow access to users having mail address <user>@MyCompany.com
plugfront.allowlist_geo_locations array of one or more two-letter country codes. If defined, clients having ip-address that do not correspond to defined country code will be denied access. Use country code PRIVATE to include 127.0.0.1 and none public ip-addresses. Note that nginx needs following configuration for including client ip-address in the PlugSSO communication: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;. This product includes GeoLite2 data file created by MAXMIND . Geolocation data file must be located at Plug-Back config/geolocation/geo.mmdb. This file is a copy of GeoLite2-Country.mmdb. Using the commercial GeoIP2 provides a higher-level api
plugfront.allowlist_users one or more login names. If defined, users having login name not defined in this list will be denied access e.g. [email protected] will only allow access to peter
plugfront.cookie cookie configuration
plugfront.cookie.httponly true or false, default true
plugfront.cookie.maxage default 0, number of minutes until cookie expires and user have to re-authenticate. Default 0 to delete the cookie when the browser is closed
plugfront.cookie.samesite_mode none, lax or strict, default none
plugfront.cookie.secure true or false, default false
plugfront.displayname product name shown in all user dialogs
plugfront.headers header configuration
plugfront.headers.claims comma separated list of claims attributes that will be assigned values if they are included by OAuth or local authentication/authorization. Nginx then having rules for including these claims attributes as header variables
plugfront.jwt JSON webtoken containing user information attached to cookie
plugfront.jwt.maxage default 240, number of minutes until jwt expires. User have to re-authenticate when expired. Should be less than cookie.maxage (if cookie.maxage > 0)
plugfront.log log configuration
plugfront.log.console true or false. When true, logging to console instead of file, and stdout/stderr redirect can then be used
plugfront.log.level error, info or debug. Logs to <plug-front>/logs/plug-front.log having file rollover at 10 MB and keeping 10 files
plugfront.listen default 0.0.0.0 accept traffic from all internal interfaces
plugfront.port default 9091, the port used by Plug-Front and reverse proxy (nginx) communicates with Plug-Front using this port
plugfront.oidc_provider OpenID Connect provider configuration
plugfront.oidc_provider.oidc_configs one or more client configuration
plugfront.oidc_provider.oidc_configs.callback_url client callback url. This url must also be included as a realm
plugfront.oidc_provider.oidc_configs.client_id self defined client id
plugfront.oidc_provider.oidc_configs.client_secret self defined client secret
plugfront.oidc_provider.signing_certificate ES256 or RS256 signing certificate. Note, certificate will be autogenerated if not defined
plugfront.oidc_provider.signing_certificate.certfile certificate file name. File must be located in <plug-front/config/certs
plugfront.oidc_provider.signing_certificate.keyfile certificate private key file name. File must be located in <plug-front/config/certs
plugfront.smtp mail configuaration. Mail is used for mail address verification and self-service otp reset code
plugfront.smtp.host mail server e.g. “smtp.office365.com”
plugfront.smtp.proxy if using mailproxy e.g. “http://proxy-host:1234”. Proxy user/password set to same as smtp.user/password
plugfront.smtp.password clear text password will become encrypted
plugfront.smtp.port port used by mailserver e.g. 587, 25 or 465
plugfront.smtp.username mail account for authentication and also the sender of the email, e.g. “[email protected]

Using environments

Configuration may also be set by using environments.

Syntax is variable names like above dotted notation, but starting with PLUGSSO_, all uppercase, and underscore instead of dots. Example (linux using “export”, windows using “set”):

export PLUGSSO_PLUGBACK_USERNAME=plugadm
export PLUGSSO_PLUGBACK_PASSWORD=password
export PLUGSSO_PLUGBACK_CLUSTERNODES=192.168.253.20

Environments may also be defined in a vault file having only the initial vaultfile defined in environment

Example:

export PLUGSSO_VAULTFILE=./config/.vaultfile

file "./config/.vaultfile" content:
PLUGSSO_PLUGBACK_USERNAME=plugadm
PLUGSSO_PLUGBACK_PASSWORD=password
PLUGSSO_PLUGBACK_CLUSTERNODES=192.168.253.20

OIDC General (provider=oidc)

A general OIDC configuration can be used by having provider: oidc In previous examples providers like azure and google have been used

oauth:
- config:
  endpoint_name: SomeOidcProvider
  provider: oidc
  auth_url: https://<host/oauth2/v1/authorize>.
  callback_url: https://<plugsso.mycompany.com>/plug/auth
  client_id: <client-id>.
  client_secret: <client-secret>.
  scopes:
  - openid
  - email
  - profile
  token_url: https://<host/oauth2/v1/token>.
  user_info_url: https://<host/oauth2/v1/userinfo>.
Config key Description
endpoint.oauth.config.endpoint_name unique endpoint name
endpoint.oauth.config.provider oidc, when using general OIDC configuration
endpoint.oauth.config.auth_url external provider authentication url
endpoint.oauth.config.callback_url Plug-Front callbak url, should be: https://<plugsso.mycompany.com>/plug/auth
endpoint.oauth.config.client_id external provider client id
endpoint.oauth.config.client_secret external provider client secret
endpoint.oauth.config.scopes openid, email, profile
endpoint.oauth.config.token_url external provider token url
endpoint.oauth.config.user_info_url external provider userinfo url

ADFS (provider=adfs)

- config:
  auth_url: https://<adfs-host>/adfs/oauth2/authorize/
  callback_url: https://<plugsso.mycompany.com>/plug/auth
  client_id: <client-id>.
  client_secret: <client-secret>.
  endpoint_name: ADFS
  provider: adfs
  scopes: null
  token_url: https://<adfs-host>/adfs/oauth2/token/

Azure

Azure configuration portal: https://portal.azure.com

  • Azure Active Directory - App registrations - New registration
  • Name = PlugSSO, Account types = Single tenant (same as AzureAdMyOrg), Redirect URI = https://<plugsso.mycompany.com>/plug/auth
  • Branding: Microsoft logon dialog box may have a logo. Logo can be added by uploading a file containing the logo
  • Authentication: Redirect URIs and account types can be changed
  • API permissions: Microsoft Graph - openid (Type = Delegated, Description = Sign users in)
  • Certificates & secrets: Create a “New client secret”.
  • Copy generated secret
  • Copy Overview - Application id
  • Secret and Application id must be defined in corresponding Plug-Back provider azure configuration as client_secret and client_id

Note, Redirect URI must match corresponding callback_url defined in the PlugSSO configuration.

Note, account types can also be defined by editing the manifest file having one of following:
“signInAudience”: “AzureAdMyOrg”
“signInAudience”: “AzureAdMultipleOrgs”
“signInAudience”: “AzureADandPersonalMicrosoftAccount” ¨

Azure PlugSSO configuration (provider=azure)

oauth:
- config:
  callback_url: https://<plugsso.mycompany.com>/plug/auth
  client_id: <azure-client-id>.
  client_secret: <azure-client-secret>.
  endpoint_name: Microsoft
  provider: azure
  tenant: AzureAdMyOrg
Config key Description
endpoint.oauth.config.provider azure, when using Azure
endpoint.oauth.config.tenant AzureAdMyOrg, AzureAdMultipleOrgs or AzureAdAndPersonalMicrosoftAccount. Note, this definition must correspond with your Azure account configuration. AzureADMyOrg: Only accounts in the organizational directory where the app is registered (single-tenant, your company). AzureADMultipleOrgs: Accounts in any organizational directory (multi-tenant, all companies in Microsoft Azure). AzureADandPersonalMicrosoftAccount: Accounts in any organizational directory (multi-tenant) and personal Microsoft accounts (@outlook.com, @hotmail.com, @live.com)

Google

Google Cloud Platform: https://console.cloud.google.com

  • APIs & Services - Credentials
  • Click CREATE CREDENTIALS, then select OAuth client ID
  • Application type = Web application
  • Name = PlugSSO
  • Authorized JavaScript origins
  • Authorized redirect URIs
  • Click CREATE
  • Copy generated “Client ID” and “Client Secret”
  • Client ID and Secret must be defined in corresponding Plug-Back provider google configuration as client_id and client_secret

Note, URIs 2 localhost is for testing purpose. Origins URI must match users application origin host URI. Redirect URI must match corresponding callback_url defined in the PlugSSO configuration.

Google PlugsSSO configuration (provider=google)

- config:
  auth_url: https://accounts.google.com/o/oauth2/auth
  callback_url: https://<plugsso.mycompany.com>/plug/auth
  client_id: <google-client-id>.
  client_secret: <google-client-secret>.
  endpoint_name: Google
  preferreddomain: gmail.com
  provider: google
Config key Description
endpoint.oauth.config.preferreddomain domain suffix to be added automatically by Google provided login dialog
endpoint.oauth.config.provider google, when using Google

GitHub (provider=github)

- config:
  auth_url: https://github.com/login/oauth/authorize
  callback_url: https://<plugsso.mycompany.com>/plug/auth
  client_id: <google-client-id>.
  client_secret: <google-client-secret>.
  endpoint_name: GitHub
  provider: github

SCIM Gateway

SCIM Gateway can be used for advanced authentication and authorization logic

For installation see: https://github.com/jelhub/scimgateway

plugin-api is supported using get or post method. For testing, the plugin should be running in debug to analyze what beeing sent by PlugSSO.

Note, in example 3 and 4 scimgateway configuration is using path: /plugsso/api
This means baseEntity=plugsso and the api is supported by plugin-api. We may use this baseEntity in plugin-api.config for additional endpoint configuration e.g. we might need the hostname, adminuser and adminpassword for connecting a spesific endpoint for handling the PlugSSO authentication and authorization request.

Following is an example of plug-api supporting PlugSSO:

plugin-api.config - port used must correspond with PlugSSO configuration:

{
  "scimgateway": {
    "port": 8890,
  ...
}

plugin-api.js - updated scimgateway.postApi method for supporting PlugSSO:

// =================================================
// postApi
// =================================================
//
// post http://localhost:8890/plugsso/api
// body example: 
// {
//  endpoint_name: 'plug-scimgateway',
//  user: { userName: 'bjensen', name: 'Bjarne Jensen', email: '', password: 'mypassword' },
//  claims: [ 'email', 'number', 'isTrue', 'myArr' ]
// }
//
// endpoint_name = PlugSSO config endpoint_name used
// user = PlugSSO userobject
// user.userName is mandatory and should always be included, rest is optional
// user.password is set for Authentication request and blank for Authorization request
//
// if Authentication request and user.email is blank, we should retrieve email from endpoint (if supported)
// and return email attribute with users mail address (even though claims does not contain attribute email)
//
// claims contains attributes to be returned if they are supported by endpoint.
// Note, claims are plugfront.header.claims attributes. These are genaral and may belong to OAuth, Directory and SCIM Gateway
// So, they may not belong to SCIM Gateway
//
// if user not authenticated/authorized OK, then throw error that includes the text "Not Authorized"
// having that text tells PlugSSO to use ban-counter and also to bring up a new logon again with an error message.
//
// returning claims example:
// {
//    "email": "[email protected]"
// }
//
scimgateway.postApi = async (baseEntity, apiObj) => {
  const action = 'postApi'
  scimgateway.logger.debug(`${pluginName} handling "${action}" apiObj=${JSON.stringify(apiObj)}`)

  try {
    if (!baseEntity && baseEntity !== 'plugsso') {
      throw new Error(`Invalid ${action} baseEntity`)
    }

    // authenticate/authorizate user
    // if password is included user must be authenticated

    // logic needed here....
    // example returning OK if password=password
    let authenticated = false
    let authorized = false
    if (apiObj.user && typeof apiObj.user.password !== 'undefined') { // password included
      if (apiObj.user.username && apiObj.user.password && apiObj.user.password === 'password') authenticated = true
    } else {
      if (apiObj.user && apiObj.user.username) authorized = true
    }

    if (!authenticated && !authorized) throw new Error('Not Authorized')

    // user authorized
    return null

    // example returning claims:
    // return { email: '[email protected]', number: 1234, isTrue: true, myArr: ["aaa", "bbb"] }
  } catch (err) {
    const newErr = err
    throw newErr
  }
}

Nginx

Nginx must be configured to validate all requests through PlugSSO. Any claim headers returned by PlugSSO can also be included as headers to the final forwarded destination.

Configuration must include the "Mandatory Start/End section" shown in example below. In addition, each proxy location section that forwards to destinatin application must include the PlugSSO authentication at the very beginning: auth_request /plug/validate;

For testing purposes the Nginx configuration example shown below is also configured to run a webserver at port 8899 that responds with a message to simulate application access. The location section defines /sso to be protected by PlugSSO and forwards to this internal webserver at port 8899. If using url’s like https://server-name/sso/app1 or https://server-name/sso/app2 and these are defined as realms in PlugSSO configuration (/sso/app1 and /sso/app2), users will be authenticated/authorized by PlugSSO.

Note, example is using TLS and a certificate is required (self-signed certificate can be used)

Nginx configuration example:

# example: https://localhost/sso/app1

worker_processes  1;
error_log  logs/error.log;

events {
  worker_connections  1024;
}

http {
  include mime.types;
  default_type application/octet-stream;
  sendfile on;
  keepalive_timeout 65;
  server_tokens off;

  # load balancing
  upstream plug-front {
     # all plug-front servers to be included
     # plug-front should be running locally and remote "backup" will only be used in case local is unavailable
      server 127.0.0.1:9090;
      server 127.0.0.1:9090 backup;
  }
  upstream app-srv {
      # all app-srv servers to be included without backup definition
      server 127.0.0.1:8899;
      server 127.0.0.1:8899;
  }

  server {
    # redirect to 443 https
    listen 80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
  }	
	
 server {
    listen 443 ssl;
    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    # current directory is <nginx-path>/conf
    ssl_certificate cert/server.cert;
    ssl_certificate_key cert/server.key;
	
    server_name _;
    root /var/www/html/;	

    proxy_buffer_size          128k;
    proxy_buffers              4 256k;
    proxy_busy_buffers_size    256k;

    # === Mandatory START ===
	
    location = /plug/validate {
      # PlugSSO validation of request (returns 401 or 200)
      proxy_pass http://plug-front/validate?url=$scheme://$http_host$request_uri;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass_request_body off;
      proxy_set_header Content-Length ""; 	  
    }

    # if validate returns `401 not authorized`, forward request to the error401 block for login
    error_page 401 = @error401;
	
    location @error401 {
      return 302 $scheme://$http_host/plug/login?url=$scheme://$http_host$request_uri;
    }
	
    location /plug {
      rewrite ^/plug/(.*) /$1 break;
      proxy_pass http://plug-front;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # === Mandatory END ===
	
    location /sso {
      # PlugSSO authentication/authorization before forward to destination
      auth_request /plug/validate;
      
      # forward to local static webserver for testing purposes
      rewrite ^/sso/(.*) /$1 break;
      proxy_pass http://app-srv;

      # Example adding user_id header based on uid claim returned by PlugSSO
      # "error_log logs/error.log debug;" will list X_Plug_Claims_<PlugSSO claim attribute> in the debug log
      auth_request_set $user_id $upstream_http_X_Plug_Claims_Uid;
      proxy_set_header user_id $user_id;
    }

  }

  server {
    # testing purpose
    listen 8899;
    server_name _;
    root /var/www/html/;

    # return a message for all locations
    add_header Content-Type text/plain;
    return 200 "Yes, you are authorized for: $request_uri";
  }

 
}