If you want to use authorization, you must first add the following configuration to shrine.conf, after the existing shrine block:
shrine { ... } ... shrine.config.authorizer.requireAuthorization = "true" shrine.webclient.ssoLogoutUrl = "https://<your hostname>/shrine-api/authorizer/logout" shrine.config.authorizer.shibLogoutUrl = "https://<your hostname>/Shibboleth.sso/Logout?return=<return URL provided by your idP>" |
The default unauthorized message is as follows and currently baked into the code: "You currently do not have access to SHRINE. Please contact your institution's SHRINE administrator for more information."
(Optional) The unauthorized message can be tailored to your needs in shrine.conf by uncommenting and updating the following line:
// shrine.webclient.unauthorizedMessage = "Enter your message" |
Phase 1: Collecting "attributes" about the user
Phase 2: Making an authorization decision based on the attributes collected in Phase 1
The authorization system works with any number of individually configured (Phase 1) attribute providers each of which can generate attributes. Further, a single (Phase 2) authorization provider, also configured here, will determine, based on the provided attributes, whether the user is authorized or not.
After the configuration items indicated above, the config file, shrine.conf, also needs a configuration called 'shrine.config.authorizer', of the following form:
// Configuration for Phase 1 (attribute providers) and Phase 2 (one authorizer) // shrine.config.authorizer : { attributeProviders : // this example uses three attribute providers -- there must be a non-empty list [ {...} // configuration for one available attribute provider {...} // configuration for one available attribute provider {...} // configuration for one available attribute provider ], authorizer : { // exactly one authorization provider must be configured ... // configuration for one available authorization provider } } |
// Structure of attribute-collection generated in Phase 1 * { * attribute type 1 -> { * attribute 1 -> [value 1, value 2, ...], * attribute 2 -> [value 1, value 2, ...], * ... * }, * attribute type 2 -> { * attribute 1 -> [value 1, value 2, ...], * attribute 2 -> [value 1, value 2, ...], * ... * }, * ... * } |
The WhiteBlackListAttrProvider queries a database's table of whitelisted and blacklisted users. Its typical configuration follows.
{ class = net.shrine.authz.providerService.attributes.WhiteBlackListAttrProvider name = wb-list, // DB config here should correspond to tomcat's Resource in its context.xml: #WhiteBlackListConfiguration database: { dataSourceFrom = "JNDI" jndiDataSourceName = "java:comp/env/jdbc/blackWhiteTableDB" timeout = "30 seconds" createTablesOnStart = false } } |
Note that the table and column names are not configurable. The db table must be named "bw_user" and the columns "ssoId", "whitelisted", and "blacklisted". As configured above, the database name is "blackWhiteTableDB"; but it could be configured to another name. Also, the context.conf file in the tomcat configuration must contain must contain the following:
<Resource name="jdbc/blackWhiteTableDB" auth="Container" type="javax.sql.DataSource" maxTotal="128" maxIdle="32" maxWaitMillis="10000" username="shrine" password="demouser" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/blackWhiteTableDB?serverTimezone=UTC" testOnBorrow="true" validationQuery="SELECT 1"/> |
It generates attributes of this shape:
wb-list: -> { isBlack -> (true/false}, isWhite -> (true/false} } |
The following attribute provider fetches data from a remote URL and extracts attributes from that data by using Regexes. As an example is extracts 2 attributes, person_id and faculty_type:
{ class = net.shrine.authz.providerService.attributes.EndpointAttrProvider name = profiles_faculty_type_and_id url = ".....{userId}....." userIdPlaceHolder="{userId}" attributeRegexes : [ { name = "person-id" regex = "PersonID=\"([0-9]+)\"" } { name = "faculty_type" regex = "<Affiliation Primary=\"true\">.*?FacultyTypeSort=\"(.)\"" } ] } |
The attributes generated by an EndpointAttrProvider as configured above will have this shape:
profiles_faculty_type_and_id -> { person-id: [...] faculty_type: [...] } |
As an example, the same attribute provider class could be configured as follows
{ class = net.shrine.authz.providerService.attributes.EndpointAttrProvider name = profiles_everything url = ".....{userId}....." userIdPlaceHolder="{userId}" attributeRegexes : [ { name = "everything" regex = "(.+)" } ] } |
The attributes generated by an EndpointAttrProvider as configured above will have this shape, where "everything" will contain the entire payload from the call to the 3rd party end-point
profiles_everything -> { everything: [...] } |
Another attribute provider extracts values from the HTTP request headers:
{ class = net.shrine.authz.providerService.attributes.RequestHeadersAttrProvider name = headers, headerNames : [ AJP_userId AJP_email AJP_firstName AJP_lastName ] } |
Finally the authorizer is named and configured. In the present case, the HmsAuthorizer, which makes use of the attributes generated by a WhiteBlackListAttrProvider and a REST call to the HMS profiles service.
authorizer : { name : net.shrine.authz.providerService.authorize.HmsAuthorizer } |
A more flexible authorizer could be the following. It concatenates all the received attributes and values, and then applies any number of Regexes to it. Authorization is granted if all regexes find a match. A "!" before a Regex means that there should not be a match.
//////////////////////////////////////////////////////////// // example of an alternate authorizer: RegexAuthorizer // //////////////////////////////////////////////////////////// authorizer : { name : net.shrine.authz.providerService.examples.RegexAuthorizer regexTerms : [ "wb-list.isBlack.false" "(wb-list.isWhite.true)|(profiles_faculty_type_and_id.faculty_type.[0-4])" "!(fp77)" ] } |
SHRINE 4.1.0 Appendix A.9 - Starting and Stopping the Software