-
Notifications
You must be signed in to change notification settings - Fork 752
Authorization plugins
The authorization framework would be useless without set of plugins. OpenGrok ships with basic set of plugins that allow for definition of flexible authorization stacks.
The UserPlugin
constructs a User
object and sets it as a request attribute. This object can be then used by other plugins down the stack. The object is constructed using properties of the request, namely its attributes and/or HTTP headers. The User
object has 2 main properties: id
and username
. The can be expanded by other plugins using %guid%
and %username%
, respectively, or referenced directly.
Name | Purpose |
---|---|
UserPrincipalDecoder |
uses getRemoteUser() Java EE API to retrieve information about the user (username ). This works for example for the HTTP Basic authentication. |
MellonHeaderDecoder |
decodes mod_mellon HTTP headers, namely MELLON_email (id ) and MELLON_username (username ) |
OSSOHeaderDecoder |
decodes Oracle SSO HTTP headers, namely osso-subscriber-dn (username ) and osso-user-guid (id ) |
<void method="add">
<object class="org.opengrok.indexer.authorization.AuthorizationPlugin">
<void property="name">
<string>opengrok.auth.plugin.UserPlugin</string>
</void>
<void property="flag">
<string>REQUISITE</string>
</void>
<void property="setup">
<void method="put">
<string>decoder</string>
<string>opengrok.auth.plugin.decoders.MellonHeaderDecoder</string>
</void>
</void>
</object>
</void>
The plugin has a special property called fake
that allows to insert custom headers
with the fake-
prefix that would be evaluated instead of the usual SSO headers.
Header insertion can be done e.g. using the Modify headers Firefox plugin.
<!-- get user cred from HTTP headers -->
<void method="add">
<object class="org.opengrok.indexer.authorization.AuthorizationPlugin">
<void property="name">
<string>opengrok.auth.plugin.UserPlugin</string>
</void>
<void property="flag">
<string>REQUISITE</string>
</void>
<!-- set fake parameter to true to allow insertion of custom headers -->
<void property="setup">
<void method="put">
<string>fake</string>
<boolean>true</boolean>
</void>
</void>
</object>
</void>
Checks a field of the User
object against a whitelist stored in a text file (one entry per line). By default the plugin checks the username
field of the User object
. It can be configured to check either the username
or the id
field.
This plugin depends on the UserPlugin
(which sets the User
object as a request attribute) so UserWhiteListPlugin
needs to be in the stack below UserPlugin
.
<void method="add">
<object class="org.opengrok.indexer.authorization.AuthorizationPlugin">
<void property="forProjects">
<void method="add">
<string>foo</string>
</void>
</void>
<void property="name">
<string>opengrok.auth.plugin.UserWhiteListPlugin</string>
</void>
<void property="flag">
<string>REQUIRED</string>
</void>
<void property="setup">
<!-- fieldName is optional. By default the username field is checked. -->
<void method="put">
<string>fieldName</string>
<string>id</string> <!-- non-default -->
</void>
<void method="put">
<string>file</string>
<string>/opengrok/etc/foo-whitelist.txt</string>
</void>
</void>
</object>
</void>
denies everything
allows everything
Each of the LDAP plugins performs a query to LDAP server to determine whether to allow the request.
All LDAP plugins can use distinct LDAP server configuration. The configuration is put info effect by using the setup
property, for example readonly configuration file will look like this:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_172" class="java.beans.XMLDecoder">
<object class="org.opengrok.indexer.configuration.Configuration" id="Configuration0">
<void property="pluginStack">
<!-- The setup will be inherited to all sub-stacks -->
<void property="setup">
<void method="put">
<string>configuration</string>
<string>/opengrok/auth/config/ldap-plugin-config-corp.yml</string>
</void>
</void>
<!-- Place for authorization sub-stacks and/or authorization plugins -->
</void>
<!-- Authorization config end -->
</object>
</java>
The LDAP server configuration is stored in separate file. It uses the YAML format.
Here is an example of the ldap-plugin-config-corp.yml
file (referenced above in the read-only configuration file):
servers:
- url: "ldap://foo.example.com"
connectTimeout: 5000
- url: "ldap://bar.example.com"
interval: 900000
searchBase: dc=example,dc=com
webHooks:
fail:
uri: "http://localhost:8080/source/api/v1/messages"
content: '{ "tags": [ "main" ], "messageLevel": "error", "text": "LDAP failed", "duration": "PT1M" }'
searchTimeout: 500
connectTimeout: 5000
countLimit: 100
Here is the list of top-level properties:
property | Type/unit | Description |
---|---|---|
interval |
milliseconds | when the whole server pool is down, wait for this amount before trying again |
searchBase |
string | LDAP search base |
webHooks |
object | list of web hooks |
countLimit |
integer | retry count of connect attempts |
connectTimeout |
milliseconds | per server pool connect timeout |
searchTimeout |
milliseconds | per server pool search timeout |
readTimeout |
milliseconds | per server pool read timeout |
servers |
object | list of LDAP servers |
List of webHooks
properties:
property | Type/unit | Description |
---|---|---|
URI |
string | URI to post HTTP request to |
content |
string | the content of the request |
LdapServer
properties:
property | Type/unit | Description |
---|---|---|
name |
string | URL of the server. Something like ldap://example.com or ldaps://example.com
|
connectTimeout |
milliseconds | per server connect timeout |
readTimeout |
milliseconds | per server read timeout |
interval |
milliseconds | per server reconnect interval (once the server fails) |
username |
string | security principal for connecting to the server. Normally this is the DN of the user. |
password |
string | security credential for connecting to the server |
The handy thing about the setup is that it can be placed right underneath the pluginStack
definition, so that it can be shared by all LDAP plugins.
Uses the information stored in the request by the UserPlugin
and performs LDAP lookup to construct LdapUser
object and stores the object as session attribute (to provide caching in order to limit the queries to LDAP servers). The other LDAP plugins can then use the DN and LDAP attributes stored in the object.
Properties:
Name | Description |
---|---|
filter |
the LDAP filter to use when looking up the LDAP object. It is important to specify the filter so that it matches one LDAP object only. The filter can use attributes of the User object, namely its id and username . |
attributes |
comma separated list of LDAP attributes to lookup and store in the LdapUser object |
instance (optional, default empty) |
instance number of the plugin. This provides naming of the session attribute so that other LDAP plugins can reference particular LdapUser object (e.g. from certain server). |
useDN (optional, default false ) |
whether to treat the username property of the User object as DN when looking up the LDAP object. This is handy in case the Identity server supplies this, e.g. useful when using OSSOHeaderDecoder . |
<void method="add">
<object class="org.opengrok.indexer.authorization.AuthorizationPlugin">
<void property="name">
<string>opengrok.auth.plugin.LdapUserPlugin</string>
</void>
<void property="flag">
<string>REQUISITE</string>
</void>
<void property="setup">
<void method="put">
<string>filter</string>
<string>(&(objectclass=person)(mail=%guid%)(uid=%username%))</string>
</void>
<void method="put">
<string>attributes</string>
<string>mail,uid</string>
</void>
</void>
</object>
</void>
Performs a check of LDAP attribute against a whitelist. It relies on the LdapUser
object to be present in the session because it uses the DN of the user to perform the lookup (to avoid unnecessary traversal of LDAP directory tree).
The whitelist file contains entries (e.g. e-mail addresses) separated by newlines.
<void method="add">
<object class="org.opengrok.indexer.authorization.AuthorizationPlugin">
<void property="name">
<string>opengrok.auth.plugin.LdapAttrPlugin</string>
</void>
<void property="flag">
<string>SUFFICIENT</string>
</void>
<void property="setup">
<void method="put">
<string>attribute</string>
<string>mail</string>
</void>
<void method="put">
<string>file</string>
<string>/opengrok/auth/config/whitelists/foo-whitelist-mail.txt</string>
</void>
</void>
</object>
</void>
Uses LDAP filter to check whether the request should be allowed. If no object is found, the request is denied.
Properties:
Name | Description |
---|---|
filter |
the LDAP filter to use when looking up the LDAP object. The filter can use attributes acquired by the LdapUserPlugin and UserPlugin . |
instance (optional, default empty) |
which instance of LdapUser object to use |
transforms (optional, default null) |
comma separated string transforms that will change the values replaced by the % wildcards, where each transform is name:value pair, allowed values: toLowerCase (convert string to lower case), toUpperCase (convert string to upper case) |
In the following example notice these things:
- per plugin LDAP server configuration is used
- the filter expands the
uid
attribute from theLdapUser
object - some special characters need to be HTML encoded in the filter string (
&
but not*
)
<void method="add">
<object class="org.opengrok.indexer.authorization.AuthorizationPlugin">
<void property="name">
<string>opengrok.auth.plugin.LdapFilterPlugin</string>
</void>
<void property="flag">
<string>REQUIRED</string>
</void>
<void property="setup">
<void method="put">
<string>configuration</string>
<string>/opengrok/auth/config/ldap-plugin-config-foo.xml</string>
</void>
<void method="put">
<string>filter</string>
<string>(&(objectclass=posixGroup)(cn=src*)(memberUid=%uid%))</string>
</void>
<void method="put">
<string>transforms</string>
<string>uid:toLowerCase</string>
</void>
</void>
</object>
</void>
Adjust the default Tomcat logging.properties
file like so:
# default handlers
handlers = 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, 3manager.org.apache.juli.AsyncFileHandler, 4host-manager.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler
...
# This limits OpenGrok logging.
java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
# Bump log level for all authorization plugins.
opengrok.auth.level = FINEST
Note: this will spew lots of output to the catalina.out
log file.