Grouper Built-in Basic Authentication to UI and Web Services
Overview
This page outlines the approach to authentication to the Grouper UI and web services in Grouper v2.5+.
Whatever authentication you may have used in the past for the Grouper UI and web services is still available. For example, if you are using Shibboleth for the UI and LDAP web service authentication, then most of this page won't apply to you (only the section on restricting source IP address).
Grouper v2.5+ provides a better built-in web service authentication method than basic auth:
Passwords are not stored in clear text in
tomcat-usersPasswords are not transmitted on the wire
Not tomcat specific (tomcat config files are painful to automate the use/removal of)
Ability to filter the source address for web services
This provides easier quick starts and bootstraps in the UI and web services. These features default to off and are enabled in config.
Who can change passwords? Admins, or admins of service accounts. Grouper assigns complex passwords.
Basic authentication built in to Grouper
If configured (for quick start only), the UI can use basic auth with passwords configured for users.
It is possible for users to reset their password using their old password to authenticate.
Built-in UI basic auth is intended for quick starts only and is off by default. It is enabled with the grouper.is.ui.basicAuthn setting (environment variable GROUPER_UI_GROUPER_AUTH); the Grouper config comment reads: "UI basic auth is for quick start. Set to false when you migrate to shib or something else." For production, authenticate the UI with Shibboleth or another SSO. (Confirmed in the supported releases.)
Passwords for web services
Your LDAP, Kerberos, Apache, or tomcat authentication still works. It is possible there could be multiple allowed — for example, to transition into local entity JWT authentication — depending on configuration.
A private-key-signed JWT is recommended with web services, or required at some sites. Source IPs can be required too.
The username is the system name of the local entity.
The private key is generated by Grouper and downloaded once.
It is not sent across the wire in web service calls.
JWT details:
To authenticate with JWT the client would:
Generate a valid JWT
jti(e.g. a UUID).Have the correct time within the configured drift, and get the seconds since 1970 (GMT).
Send a "Bearer" authorization header
sfdlh23kjh.kjhsdfkjhsf.kjh345kjhkjh(three parts separated by a dot).The first part is the header, base64 url encoded:
{ alg: "RS-256", typ: "JWT" }The second part is what makes the token unique and identifies the user:
jtiis a unique value per request (across clusters) and cannot be re-used, e.g. a UUID.usernameis the system name of the local entity.iatis the number of seconds since 1970 that the ticket is issued; the value received on the server needs to be within the allowable time drift.{ jti: "abc123", username: "org:businessSchool:credentials:wiki", iat: 1234567 }
Thus the same request cannot be replayed.
The JWT validity window defaults to 600 seconds (10 minutes) and is configurable via grouper.selfService.jwt.maxValidTimeInSeconds. A received iat outside this window is rejected. (Default confirmed in the supported releases.)
Manage passwords
The UI lets admins set a user's (or local entity's) UI password and restrict source IP CIDRs. UI passwords must follow strength rules.
The UI also lets admins, or end users (self-serve), download a newly generated web service private key or password for a local entity they can ADMIN, and restrict source IP CIDRs:
Someone who can create in a folder (and optionally in a group that controls who can create web service credentials)
Create a local entity
Download its password or private key (can only be downloaded once)
Grant privileges to the local entity
Use it in web service calls
Admins and end users cannot view or re-download passwords or private keys.
Add a UI password via GSH
Use your own random password, not A4JKnXx3lSn4CmvqUiZ4.
//v2.5.29+
new GrouperPasswordSave().assignApplication(GrouperPassword.Application.UI).assignUsername("GrouperSystem").assignPassword("A4JKnXx3lSn4CmvqUiZ4").save();
Add a web service password via GSH
Note: if you are setting a password for a local entity to make web service calls, you should probably use the UUID (unique id) as the username, though the system name (id) might work too (it works in the Grouper client). Colons shouldn't be used in HTTP usernames, so the UUID is better.
//v2.5.29+
new GrouperPasswordSave().assignApplication(GrouperPassword.Application.WS).assignUsername("GrouperSystem").assignPassword("A4JKnXx3lSn4CmvqUiZ4").save();
//Local entity with uuid
new GrouperPasswordSave().assignApplication(GrouperPassword.Application.WS).assignUsername("7a7937ad646849fc8278fb2fc6c45156").assignPassword("A4JKnXx3lSn4CmvqUiZ4").save();
Example: local entity with web service authentication
Start the quickstart (example with the v2.5.36 container):
docker run --detach --name grouper-qs \
--publish 443:443 -e GROUPER_MORPHSTRING_ENCRYPT_KEY=abcdefg12345dontUseThis \
-e GROUPERSYSTEM_QUICKSTART_PASS=A4JKnXx3lSn4CmvqUiZ4 i2incommon/grouper:2.5.36 quickstartNote: quickstart sets this environment variable: GROUPER_WS_GROUPER_AUTH=true
Add a local entity:
Set a password:
mchyzer@ISC20-0637-WL:~/container$ docker exec -it -u tomcat grouper-qs bash
[tomcat@f7adb51426d3 WEB-INF]$ cd bin
[tomcat@f7adb51426d3 bin]$ ./gsh.sh
groovy:000> new GrouperPasswordSave().assignApplication(GrouperPassword.Application.WS).assignUsername("7a7937ad646849fc8278fb2fc6c45156").assignPassword("A4JKnXx3lSn4CmvqUiZ4").save();
groovy:000> :q
[tomcat@f7adb51426d3 bin]$ exitMake a group test:testGroup, allow test:localEntity to READ it, and add GrouperSystem as a member.
Call the web service with the Grouper client:
mchyzer@ISC20-0637-WL:~/container$ docker cp grouper-qs:/opt/grouper/grouperWebapp/WEB-INF/lib/grouperClient-2.5.36.jar .
mchyzer@ISC20-0637-WL:~/container$ vi grouper.client.properties
grouperClient.webService.url = https://localhost:443/grouper-ws/servicesRest
grouperClient.webService.login = 7a7937ad646849fc8278fb2fc6c45156
grouperClient.webService.password = A4JKnXx3lSn4CmvqUiZ4
# turn off SSL until a real SSL certificate is installed
# NOTE, THIS IS NOT GOOD SECURITY AND IS FOR THE QUICK START ONLY!
grouperClient.https.customSocketFactory = edu.internet2.middleware.grouperClient.ssl.EasySslSocketFactory
mchyzer@ISC20-0637-WL:~/container$ java -jar grouperClient-2.5.36.jar --operation=getMembersWs --groupNames=test:testGroup
GroupIndex 0: success: T: code: SUCCESS: group: test:testGroup: subjectIndex: 0: GrouperSystemOr with curl:
mchyzer@ISC20-0637-WL:~/container$ curl --insecure --user 1ebc381f335c4c6f8dadfc5b76e85dc8:A4JKnXx3lSn4CmvqUiZ4 https://localhost:443/grouper-ws/servicesRest/v2_5_000/groups/test%3AtestGroup/membersDatabase reference
Built-in authentication state lives in two Grouper-managed tables. You do not edit them directly, but it helps to know they exist:
grouper_password— one row per credential. A username or local entity can have both a UI and a web service credential, distinguished by theapplicationcolumn (uiorws). Passwords are stored salted and hashed and web service keys as encrypted public keys — never in clear text. Theallowed_from_cidrscolumn restricts the source network a credential may be used from; this source-address restriction applies even when Grouper itself is not performing the authentication.grouper_password_recently_used— supports JWT replay protection. Each accepted JWTjtiis recorded so the same token cannot be replayed, and a daemon clears entries once they age past the validity window (see above).
The authoritative column-level schema lives in the Grouper source (GrouperPassword.java and the GrouperDdl2_* classes) and changes across versions, so it is intentionally not duplicated here.