# Login methods, OIDC & SAML
This documentation is valid for Onezone version 19.02.* or newer (config version 3
).
OpenID Connect and SAML are the main authentication mechanisms used in Onedata. They allow users to reuse their accounts from other websites such as social media or infrastructure portals (Single Sign-On).
As a Onezone admin, your job is to decide which Identity Providers (IdPs) will be supported and to configure the authentication methods accordingly.
To that end, you will be editing the /etc/oz_worker/auth.config
file on the Onezone
node(s). In a docker-compose
deployments, the most straightforward method is to mount
the auth.config
file in the volumes section.
NOTES
The
auth.config
typically includes secrets and sensitive information; do not put it in your version control repository.Make sure to always specify the
version => 3,
at the top of your config.The
auth.config
file must be present on all cluster nodes hosting the Onezone worker service and must be identical.
# Table of contents
- Table of contents
- Quickstart
- Automatic config upgrade
- Prerequisites
- The login page
- Config file structure
- Auth plugins
- Troubleshooting
- LUMA Integration
- Custom icon guidelines
- Test login page
- Complete example
- Minimal config
- Exemplary entries for selected IdPs
- Username & password login
- KeyCloak config (OpenID Connect)
- GitHub config (OpenID Connect)
- Google config (OpenID Connect)
- Facebook config (OpenID Connect)
- EGI config (OpenID Connect)
- PLGrid config (OpenID 2.0)
- CERN config (SAML)
- CNRS config (SAML)
- DESY config (SAML)
- Elixir config (SAML)
- EMBL config (SAML)
- ESRF config (SAML)
- IFAE config (SAML)
- INFN config (SAML)
- KIT config (SAML)
- STFC config (SAML)
- UnitedID config (SAML)
# Quickstart
By default, Onezone is packaged with a configuration that enables only Basic authentication,
placed in /etc/oz_worker/auth.config
. After deploying Onezone, a default user admin
will be created, with a password equal to the emergency passphrase provided in Onepanel
during deployment — this way you can log in to a fresh Onezone installation without
further setup.
TIP
Deployment examples using docker-compose
overwrite the auth.config
file with a mount
from the host. Simply remove this mount to use the default config (especially when you are
not sure how to fill it in because mounting an incorrect config will disable all login
methods). Here (opens new window) is the minimal auth.config
that is installed by default.
You can follow the tutorial for Google IdP if you wish to enable login with a Google account.
# Automatic config upgrade
During the first startup after upgrading Onezone to a newer version, Onezone will attempt
to automatically upgrade the config file to the latest version. In such a case, the old
config file (auth.config
) will be backed up to auth.config.v{vsn}.bak
. The information
on whether the upgrade has been successful will be present in Onezone logs. Always
examine the upgraded auth.config
file to make sure that it was correctly converted.
The current config version is 3
and has not changed since the quite old Onezone version
19.02.1, so an upgrade will likely not be required.
# Prerequisites
To integrate with an OpenID or SAML Identity Provider, you need to have a basic knowledge of those protocols and interact with the Identity Providers to obtain all required information, register your services, etc. In general, the necessary steps are:
# OpenID Connect
Make sure your Onezone service is up and running on your domain, let it be
onezone.example.com
for the sake of this tutorial.Visit the official documentation or website of the Identity Provider you wish to use and find out the process of integration, which can be a bit different for each one. The process might be automatic (an online form or control panel), or require contact with the administrators.
You will have to register your OpenID Connect client (Onezone), providing information such as domain, service name, etc. When asked for Redirection Endpoint (URL), specify the following:
https://onezone.example.com/validate_login
After finishing the registration process, you will be assigned a Client ID and a Client Secret.
In the supported IdP list, create a new element by choosing a unique identifier (e.g.
google
). Fill out all the required information, including the Client ID and Secret. Theprotocol
attribute must be set toopenid
.Depending on the IdP, there might be more configuration options regarding the OpenID flow — some of them are reflected in the plugin config.
Put the
auth.config
on the machine running Onezone under/etc/oz_worker/auth.config
and wait for up to a minute (default config caching time), or restart the Onezone service for immediate effect.You should see your IdP on the login page, verify that it works correctly by clicking on its icon to go through the login process. In case of any errors, examine the Onezone logs.
At any time, you can use the test login page to test your auth.config without interrupting the Onezone service.
# SAML
Make sure your Onezone service is up and running on your domain, let it be
onezone.example.com
for the sake of this tutorial.Generate a strong RSA x509 key pair (can be self-signed) and put them on your Onezone host — a tutorial can be found here (opens new window).
Decide on your SAML Entity ID which is typically constructed using your domain, e.g.
https://onezone.example.com/sp
. It does not have to point to an existing resource,Fill out the SAML Config section of the
auth.config
, putting down all the required information, including the Entity ID and paths to the key and cert.Put the
auth.config
on the machine running Onezone under/etc/oz_worker/auth.config
and wait for up to a minute (default config caching time), or restart the Onezone service for immediate effect.Visit
https://onezone.example.com/saml/sp.xml
and verify that the advertised metadata is correct. In case of any errors, examine Onezone logs.Visit the official documentation or website of the Identity Provider you wish to use (e.g. eduGAIN) and find out the process of integration, which can be a bit different for each one. The process might be automatic (an online form or control panel), or require contact with the administrators.
Register your SAML Service Provider (Onezone). During the process, you will most probably be required to provide the URL to the SAML SP Metadata (pt. 6), or provide a static XML with the metadata (which can be simply downloaded from this endpoint).
Create a new element in the supported IdP list, choose a unique identifier (e.g.
elixir
), and fill out all the information. Theprotocol
attribute must be set tosaml
.Reload the
auth.config
again (pt. 5).You should see your IdP on the login page, verify that it works correctly by clicking on its icon to go through the login process. In case of any errors, examine Onezone logs.
At any time, you can use the test login page to test your auth.config without interrupting the Onezone service.
# The login page
After adding your IdPs to the config file, you should see the corresponding icons on
the login page (https://onezone.example.com
). If there are more than 7 IdPs,
the first 6 will be shown and the rest hidden in the ...
button.
# Config file structure
This section discusses the exemplary auth.config
file that can be found in
/etc/oz_worker/template.auth.config
on the machine running Onezone. The complete
exemplary config file is presented at the end of this section.
# General remarks
The auth.config
file is written in Erlang format, quite similar to JSON:
#{Key1 => Value1, Key2 => Value2}
is a key-value map (can be nested),[ ... ]
is a list,{A, B}
is a two-value tuple,undefined
is a specialatom
indicating that the given parameter is not specified (null
),"some text"
is a string,% ...
is a comment,true
orfalse
is a boolean value.
# Main sections
The config file has the following sections:
#{
version => 3,
% Allows to log in to Onezone using username & password.
basicAuthConfig => #{
enabled => true
},
openidConfig => #{
enabled => true,
...
},
samlConfig => #{
enabled => true,
...
},
supportedIdps => [
...
]
}
version
— an obligatory field that defines the version of the config file,
currently the newest is 3
. If no version field is found, version 1
is
assumed. Used by Onezone to determine if an upgrade is required.
# Basic auth config
basicAuthConfig
— this section enables or disables Basic Auth — the possibility
to log in to Onezone using username & password. This also controls the
possibility of authorizing Onezone REST API operations using basic credentials.
NOTES
To allow Basic Auth login via the Onezone login page, the enabled
flag must be set to
true
and the basicAuth
method must be included on the supported IdP list.
The default admin
user is always created during the installation process. Additional
users can be created using the REST API (opens new window).
Disabling any protocol using the enabled
flag in basicAuthConfig
, openidConfig
, or
samlConfig
section will disable all IdPs using that protocol and hide them from the
login screen.
# OpenID config
openidConfig
— this section contains common OpenID configuration and defaults
that will be inherited by all OpenID IdPs.
click to expand
openidConfig => #{
% Enable OpenID login protocol — if disabled, all OpenID IdPs will be
% hidden from the login page.
enabled => true,
% Default config for every OpenID IdP, can be overridden in IdP config
defaultProtocolConfig => #{
% Internal plugin that will be used for handling the login process -
% if the IdP uses standard OpenID Connect protocol,
% default_oidc_plugin is the way to go. If not, IdP specific plugin
% can be implemented and specified here.
plugin => default_oidc_plugin,
% Config specific for default_oidc_plugin
pluginConfig => #{
% Scope requested from OpenID Connect IdP
scope => "openid email profile",
% HTTP method used to exchange auth code for an access token: post | get
accessTokenAcquireMethod => post,
% How the client secret should be sent to the IdP: urlencoded | inAuthHeader
clientSecretPassMethod => urlencoded,
% How user's access token should be sent to the IdP: urlencoded | inAuthHeader
accessTokenPassMethod => inAuthHeader,
% Allows to augment requests with additional data
customData => #{
% Additional data for access_token endpoint request
accessToken => #{
% query string or post body parameters (key-value)
parameters => undefined,
% headers (key-value)
headers => undefined
},
% Additional data for userinfo endpoint request
userInfo => #{
parameters => undefined,
headers => undefined
}
}
},
% Enables/disables authorization using access tokens from the IdP
% Supported only in OpenID protocol
authorityDelegation => #{
% Enabled for this IdP
enabled => true
% The tokenPrefix attribute defines a prefix used to distinguish
% tokens from given IdP. It defaults to "<idp>:", where <idp> is
% the identifier used in config. Can be overriden in IdP config,
% like the following:
% tokenPrefix => "my-idp/"
% Exemplary token usage with with such config:
% curl -H "X-Auth-Token: my-idp/lkj9s87rf1234SDfh6721hqd7991" ...
},
% If enabled, Onezone will ask for refresh tokens and store them so
% that it is later possible to acquire user's access token issued by
% given IdP without him being logged in. Only OIDC IdPs are supported.
offlineAccess => true,
% Defines how the attributes from OpenID user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% OpenID attributes.
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => {optional, "groups"},
custom => {optional, "name"}
},
% Rules for mapping entitlements in the IdP into entitlements in Onedata.
entitlementMapping => #{
enabled => false
}
}
},
More details:
plugin
— specifies the Erlang module that handles the login process. If not specified, it defaults todefault_oidc_plugin
, which can handle most standard OpenID Connect IdPs. It is possible to implement your own, specialized plugin. Currently, Onezone supports oneOpenID 1.0
IdP — the PLGrid organization that usesplgrid_openid_plugin
— see this example.pluginConfig
— config specific for thedefault_oidc_plugin
— see below.authorityDelegation
— see below.offlineAccess
— see below.attributeMapping
— see below.entitlementMapping
— see below.
# SAML config
samlConfig
— similarly to openidConfig
, this section contains common SAML
configuration and defaults that will be inherited by all SAML IdPs.
click to expand
samlConfig => #{
% Enable SAML login protocol — if disabled, all SAML IdPs will be hidden
% from the login page and the endpoint serving SAML metadata will be
% disabled.
enabled => true,
% Information used to build SAML SP metadata XML, refer to SAML
% documentation for details on below attributes.
spConfig => #{
entityId => "https://onezone.example.com/sp",
certFile => "/etc/oz_worker/certs/saml_cert.pem",
keyFile => "/etc/oz_worker/certs/saml_key.pem",
organizationName => "My organization",
organizationDisplayName => "My organization",
techContactName => "John Doe",
techContactEmail => "john.doe@onezone.example.com",
% Should the metadata be signed with keyFile
signMetadata => false,
% Should the Auth Requests be signed with keyFile
signRequests => true,
% Should Onezone request signed assertions
wantAssertionsSigned => true
},
% Default config for every SAML IdP, can be overridden in IdP config
defaultProtocolConfig => #{
% SSO binding — defines what type of request should be performed
% to redirect the user to the IdP's login page. Possible values:
% http_redirect (default) or http_post
preferredSsoBinding => http_redirect,
% Defines how the attributes from SAML user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% SAML attributes.
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {required, {any, ["displayName", "surName"]}},
username => {optional, "eduPersonPrincipalName"},
emails => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => {optional, "eduPersonScopedAffiliation"}
},
% Rules for mapping entitlements in IdP into entitlements in Onedata.
entitlementMapping => #{
% Enable / disable entitlement mapping for given IdP
enabled => true,
% The name of the parent group to which all groups from this IdP
% will belong (reflecting a Virtual Organization)
voGroupName => undefined,
% A special group that has admin rights to all groups from this
% IdP.
adminGroup => undefined,
% Erlang module (plugin) that will be used to parse user's
% entitlements from this IdP
parser => nested_entitlement_parser,
% Config specific for the nested_entitlement_parser
parserConfig => #{
splitWith => "/",
topGroupType => unit,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => member
}
}
}
},
More details:
spConfig
— information put here will be used to build the SAML Service Provider XML, which will be advertised underhttps://onezone.example.com/saml/sp.xml
. Remember that paths provided in the key/cert field must point to existing files, otherwise the XML will not be generated. Refer to SAML documentation for details on certain fields.attributeMapping
— see belowentitlementMapping
— see below
# Supported IdPs
This section provides a list of all IdPs that will be available on the login page. The button order on the login page corresponds to the order of the entries:
click to expand
supportedIdps => [
% IdP identifier, must be a unique, arbitrary atom
{myIdP, #{
% Configuration of the login page button
displayName => "My IdP",
% Some predefined icons are built-in into the GUI app.
% Their paths start with /assets/images/auth-providers.
% For a custom icon, put it in:
% /var/www/html/oz_worker/custom/<path>
% and reference it here like this: /custom/<path>
iconPath => "/assets/images/auth-providers/default.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any) for better visual effect.
iconBackgroundColor => "#4BD187",
% Which protocol is used for this IdP
protocol => openid,
% Config specific for given protocol
protocolConfig => #{
...
}
}},
{anotherIdP, #{
...
}},
...
]
More details:
- The IdP identifier (
myIdP
in this example) — must be unique across theauth.config
file and be an Erlang atom (basically starting with a lowercase letter and containing only letters or underscores).
NOTE
The identifier basicAuth
is reserved for Basic Auth and the more
identifier is reserved for internal purposes and cannot be used.
iconPath
— the path to the static image file that will be used for the IdP icon on the login page. Some predefined icons are available under the path/assets/images/auth-providers/<icon>.svg
, to see the full list visit the Onezone GUI repo (opens new window). You will find information on how to add custom icons to the login page here. If not specified,iconPath
defaults to/assets/images/auth-providers/default.svg
.protocol
— one ofbasicAuth
,saml
,openid
.protocolConfig
— depends on the protocol, see the following sections for config examples for each protocol.
# Basic Auth example
click to expand
% basicAuth is a special IdP id reserved for signing in with username & password
% and the only valid config entry using the basicAuth protocol.
{basicAuth, #{
% Configuration of the login page button
displayName => "username & password",
% Some predefined icons are built-in into the GUI app.
% Their paths start with /assets/images/auth-providers.
% For a custom icon, put it in:
% /var/www/html/oz_worker/custom/<path>
% and reference it here like this: /custom/<path>
iconPath => "/assets/images/auth-providers/basicauth.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any).
iconBackgroundColor => "#4BD187",
% Which protocol is used for this IdP — basicAuth is the only
% valid one for basicAuth IdP.
protocol => basicAuth
}},
# OpenID example
click to expand
{google, #{
% Configuration of the login page button
displayName => "Google",
% Some predefined icons are built-in into the GUI app.
% Their paths start with /assets/images/auth-providers.
% For a custom icon, put it in:
% /var/www/html/oz_worker/custom/<path>
% and reference it here like this: /custom/<path>
iconPath => "/assets/images/auth-providers/google.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any).
iconBackgroundColor => "#F1514F",
% Which protocol is used for this IdP
protocol => openid,
% Configuration specific for OpenID protocol — overrides the default
protocolConfig => #{
% Internal plugin that will be used for handling the login process -
% if the IdP uses standard OpenID Connect protocol,
% default_oidc_plugin is the way to go. If not, IdP specific plugin
% can be implemented and specified here.
plugin => default_oidc_plugin,
% Config specific for default_oidc_plugin
pluginConfig => #{
% Client Id and secret acquired during registration
clientId => "****************************************************",
clientSecret => "****************************************************",
% Defines how to resolve OpenID endpoints
endpoints => #{
% The XRDS endpoint, will be used if referenced in below endpoints
xrds => "https://accounts.google.com/.well-known/openid-configuration",
% standard OIDC endpoints — literal URLs or tuples {xrds, "key"} -
% "key" will be extracted from the XRDS JSON.
authorize => {xrds, "authorization_endpoint"},
accessToken => {xrds, "token_endpoint"},
userInfo => {xrds, "userinfo_endpoint"}
},
% Scope requested from OpenID Connect IdP
scope => "openid email profile",
% HTTP method used to exchange auth code for an access token: post | get
accessTokenAcquireMethod => post,
% How the client secret should be sent to the IdP: urlencoded | inAuthHeader
clientSecretPassMethod => urlencoded,
% How user's access token should be sent to the IdP: urlencoded | inAuthHeader
accessTokenPassMethod => inAuthHeader,
% Allows to augment requests with additional data
customData => #{
% Additional data for access_token endpoint request
accessToken => #{
% query string or post body parameters (key-value)
parameters => #{"param1" => "val1"},
% headers (key-value)
headers => #{"header1" => "val1"}
},
% Additional data for userinfo endpoint request
userInfo => #{
parameters => #{"param2" => "val2"},
headers => #{"header2" => "val2"}
}
}
},
% Enables/disables authorization using access tokens from the IdP
% Supported only in OpenID protocol
authorityDelegation => #{
% Enabled for this IdP
enabled => true,
% The tokenPrefix attribute defines a prefix used to distinguish
% tokens from given IdP.
% Exemplary token usage with the below such config:
% curl -H "X-Auth-Token: google:lkj9s87rf1234SDfh6721hqd7991" ...
tokenPrefix => "google:"
},
% If enabled, Onezone will ask for refresh tokens and store them so
% that it is later possible to acquire user's access token issued by
% given IdP without him being logged in. Only OIDC IdPs are supported.
offlineAccess => true,
% Defines how the attributes from OpenID user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% OpenID attributes.
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => {optional, "given_name"},
custom => {optional, "given_name"}
},
% Rules for mapping entitlements in the IdP into entitlements in Onedata.
entitlementMapping => #{
enabled => true,
% The name of the parent group to which all groups from this IdP
% will belong (reflecting a Virtual Organization)
voGroupName => undefined,
% A special group that has admin rights to all groups from this
% IdP.
adminGroup => undefined,
parser => flat_entitlement_parser,
parserConfig => #{
groupType => team,
groupPrivilegesInVo => member,
userPrivileges => member
}
}
}
}},
This IdP will inherit all the configuration from openidConfig -> defaultProtocolConfig
,
apart from the parameters that are overridden here.
TIP
To nullify a parameter specified in the default config, set it explicitly to undefined
in the IdP config — otherwise, it will be inherited.
More details on pluginConfig
:
endpoints
— this section defines how to resolve standard OpenID endpoints (authorize
,accessToken
,userInfo
). Most IdPs use an XRDS endpoint to serve a JSON containing all required URLs. To use the XRDS, simply specify thexrds
field and reference the desired keys from the JSON, like in the example above. Alternatively, you can directly enter the URLs, eliminating the need for an XRDS endpoint. TheuserInfo
endpoint is a special case that allows you to specify multiple endpoints. Information gathered from them will be aggregated, like in this example:
endpoints => #{
authorize => "https://github.com/login/oauth/authorize",
accessToken => "https://github.com/login/oauth/access_token",
userInfo => [
"https://api.github.com/user",
{"emails", "https://api.github.com/user/emails"}
]
},
In the above example, JSON collected from "https://api.github.com/user"
will
be appended as-is to user attributes, and the JSON from
"https://api.github.com/user/emails"
will be inserted under the key "emails"
.
scope
— what attributes are requested from the IdP. Defaults to"openid email profile"
.accessTokenAcquireMethod
—get
orpost
, defines the HTTP method used to exchange theauth code
for an access token. Defaults topost
.clientSecretPassMethod
—urlencoded
orinAuthHeader
, defines how the Client ID and Secret should be sent to the IdP's access token endpoint. Defaults tourlencoded
.accessTokenPassMethod
—urlencoded
orinAuthHeader
, defines how the Access Token should be sent to the IdP'suserInfo
endpoint. Defaults tourlencoded
.customData
— allows augmenting requests to the IdP with arbitrary data, appended to the request data (query string or post body) or headers. Can be specified foraccessToken
oruserInfo
endpoints.
Refer to the IdP's documentation to find out what should be inserted in the
attributes: endpoints
, scope
, accessTokenAcquireMethod
,
clientSecretPassMethod
, accessTokenPassMethod
, customData
.
Note that some of them can be configurable on the IdP side too.
# SAML example
click to expand
{elixir, #{
% Configuration of the login page button
displayName => "Elixir",
% To use the icon like below, put it in:
% /var/www/html/oz_worker/custom/images/elixir.svg
iconPath => "/custom/images/elixir.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any).
iconBackgroundColor => "#FF7A04",
% Which protocol is used for this IdP
protocol => saml,
% Configuration specific for SAML protocol — overrides the default
protocolConfig => #{
% URL pointing to IdP SAML metadata XML
metadataUrl => "https://login.elixir-czech.org/proxy/saml2/idp/metadata.php",
% SSO binding — defines what type of request should be performed
% to redirect the user to the IdP's login page. Possible values:
% http_redirect (default) or http_post
preferredSsoBinding => http_redirect,
% Defines how the attributes from SAML user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% SAML attributes.
attributeMapping => #{
subjectId => {required, "eduPersonUniqueId"},
fullName => {required, "displayName"},
username => {optional, "eduPersonPrincipalName"},
emails => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => {optional, "eduPersonScopedAffiliation"}
},
% Rules for mapping entitlements in IdP into entitlements in Onedata.
entitlementMapping => #{
% Enable / disable entitlement mapping for given IdP
enabled => true,
% The name of the parent group to which all groups from this IdP
% will belong (reflecting a Virtual Organization)
voGroupName => "Elixir",
% A special group that has admin rights to all groups from this
% IdP.
adminGroup => "elixir_test:tsi-admin",
% Erlang module (plugin) that will be used to parse user's
% entitlements from this IdP
parser => nested_entitlement_parser,
% Config specific for the nested_entitlement_parser
parserConfig => #{
splitWith => ":",
topGroupType => unit,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => member
}
}
}
}}
]
This IdP will inherit all the configuration from samlConfig -> defaultProtocolConfig
,
apart from the parameters that are overridden here.
TIP
To nullify a parameter specified in the default config, set it explicitly to undefined
in the IdP config — otherwise, it will be inherited.
Unlike openid
, SAML IdPs do not have pluggable handlers and hence there is
no plugin
or pluginConfig
section (all config is expressed on the
procotolConfig
level).
# OpenID & SAML similarities
Note that the following sections in protocolConfig
of openid
and saml
protocols are syntactically and functionally the same:
However, only the openid
protocol supports
authority delegation and offline access.
# Authority Delegation
Onezone service supports authority delegation using other OpenID connect providers. When enabled, it allows users to directly use their access tokens acquired from IdPs (e.g. from GitHub) to authorize operations in Onezone.
To enable this feature for specific IdP, the authorityDelegation
section has to be added
to the IdP's protocol config, for instance:
authorityDelegation => #{
% Enabled for this IdP
enabled => true,
% The tokenPrefix attribute defines a prefix used to distinguish
% tokens from given IdP. It defaults to "<idp>:", where <idp> is
% the IdP identifier used in config.
tokenPrefix => "github/"
},
In such case, users can directly access the Onezone API using access tokens
obtained from the IdP by prefixing the access token and placing it in the
X-Auth-Token
or Authorization: Bearer <token>
header:
X-Auth-Token: github/e72e16c7e42f292c6912e7710c838347ae178b4a
# is equivalent to
Authorization: Bearer github/e72e16c7e42f292c6912e7710c838347ae178b4a
where e72e16c7e42f292c6912e7710c838347ae178b4a
is the actual GitHub access token.
# Offline access
Onezone service can act as a dispenser for access tokens issued by IdPs that users are logging in with. If offline access is enabled in the configuration, Onezone will request refresh tokens and store them. This enables later acquisition of a user's access token, issued by a specific IdP, even if the user is not currently logged in. Only OIDC IdPs are supported, and offline access must be supported by the given IdP.
To enable this feature for specific IdP, the offlineAccess
field has to be added to the
IdP's protocol config, for instance:
offlineAccess => true,
TIP
Enabling offlineAccess
will cause Onezone to add the access_type=offline
parameter to
OIDC authorization requests. Some IdPs might also require adding the offline_access
scope, in which case you must add it manually in the scope
field of the plugin config.
WARNING
When offline access is combined with enabled authority delegation, it is important to consider the security implications. With authority delegation, every Onedata provider actively used by a user will have the ability to acquire the user's IdP access token. As a result, these providers will be able to gain full authorization on behalf of the user.
IdP access tokens can be acquired using the Onezone REST API (opens new window).
# Attribute Mapping
Onezone collects information about users from SAML / OpenID, including:
subjectId
— user's unique, permanent ID assigned by the IdP, mandatory (login will fail if mapping cannot be found),fullName
— given names and surname, e.g."John Doe"
,username
— a human-readable identifier, unique across the system, e.g."johndoe13"
. This makes it easier to identify the user and can be used for signing in with a password (if this sign-in method is enabled for the given user),emails
— a list of user's emails,entitlements
— a list of user's entitlements to groups in the IdP, which can later be mapped to groups in Onedata using entitlement mapping,custom
— arbitrary JSON received from the IdP, which can be useful during later integration with storage systems (Local User Mapping (LUMA)).
These attributes constitute a linked account object. It can be expressed in JSON format:
{
"idp": "elixir",
"subjectId": "1234567890@elixir-europe.org",
"fullName": "John Doe",
"username": "jodoe",
"emails": ["john.doe@google.com"],
"entitlements": ["group1", "group2"],
"custom": {
"organization": "My Organization",
"roles": ["role1", "role2", "role3"]
}
}
Attribute mapping is used to map attributes received from Identity Providers into linked account objects in Onedata.
# Merging linked accounts into Onedata user
Every user in Onedata can have one or more linked accounts. Upon the first login, a new Onedata user is created based on information gathered from the IdP that he logged in with:
userId: md5(<IdP>:<subjectId>)
fullName: <fullName> % can be undefined
username: <username> % can be undefined
emails: <emails>
linkedAccounts: [<linked-acc-json>]
From now on, userId
in Onedata will not change (i.e. it is derived from the
subjectId
in the first IdP the user has logged in with). fullName
and
username
will also be unchanged by consecutive log-ins, even if the IdP
attributes change. emails
are always a list of emails aggregated from all
linked accounts.
TIP
New accounts can be linked after logging in, in the user profile menu. It is not possible to link the same account to two different users.
Complete user data, after logging in with the above Elixir account, would look like the following:
{
"userId": "fa81af19783e3eea7d7e80c1d89f5370",
"fullName": "John Doe",
"username": "jodoe",
"emails": ["john.doe@google.com"],
"linkedAccounts": [{
"idp": "elixir",
"subjectId": "1234567890@elixir-europe.org",
"fullName": "John Doe",
"username": "jodoe",
"emails": ["john.doe@google.com"],
"entitlements": ["group1", "group2"],
"custom": {
"organization": "Elixir",
"roles": ["role1", "role2", "role3"]
}
}]
}
Assume that the user links another account, e.g. from EGI, which yields the following linked account object:
{
"idp": "egi",
"subjectId": "12345678-1234-1234-1234-12345678",
"fullName": "John Doe",
"username": "john-doe",
"emails": ["john.doe@yahoo.com"],
"entitlements": [
"urn:mace:egi.eu:group1#aai.egi.eu",
"urn:mace:egi.eu:group2#sso.egi.eu"
],
"custom": {
"gender": "M"
}
}
After that operation, the complete user data would look like the following:
{
"userId": "fa81af19783e3eea7d7e80c1d89f5370",
"fullName": "John Doe",
"username": "jodoe",
"emails": ["john.doe@google.com", "john.doe@yahoo.com"],
"linkedAccounts": [{
"idp": "elixir",
"subjectId": "1234567890@elixir-europe.org",
"fullName": "John Doe",
"username": "jodoe",
"emails": ["john.doe@google.com"],
"entitlements": ["group1", "group2"],
"custom": {
"organization": "Elixir",
"roles": ["role1", "role2", "role3"]
}
},{
"idp": "egi",
"subjectId": "12345678-1234-1234-1234-12345678",
"fullName": "John Doe",
"username": "john-doe",
"emails": ["john.doe@yahoo.com"],
"entitlements": "entitlements": [
"urn:mace:egi.eu:group1#aai.egi.eu",
"urn:mace:egi.eu:group2#sso.egi.eu"
],
"custom": {
"gender": "M"
}
}]
}
This user data is used as input in Local User Mapping (LUMA) — when mapping Onedata users into storage users within Oneprovider.
TIP
The user data can also be retrieved using the REST API (opens new window).
# Attribute mapping rules
Attribute mapping is performed based on the IdP configuration in auth.config
.
The section looks like the following:
attributeMapping => #{
subjectId => {required, <rule>},
fullName => {optional, <rule>},
username => undefined,
emails => {optional, <rule>},
entitlements => {plugin, my_entitlement_parser},
custom => {required, <rule>}
}
Allowed mappings are:
undefined
— this attribute is not mapped at all, it is equivalent to deleting the attribute mapping completely from the config.{required, <rule>}
— this attribute will be mapped according to<rule>
, if it's not possible to resolve the attribute the login will fail.{optional, <rule>}
— this attribute will be mapped according to<rule>
, if it's not possible to resolve the attribute the mapped value will be empty (undefined).{plugin, Module}
— allows using an arbitrary plugin to perform the mapping.Module:map_attribute(Attr, IdPAttributes)
will be called and should return the resolved attribute value as{ok, Value}
, or{error, Reason}
if it could not be found. TheIdPAttributes
argument is an Erlang map (keys are binaries). The module must be placed in the plugin directory (opens new window). For more info, refer to attribute mapper. Here is an example:
fullName => {plugin, my_attr_mapper}
% would call my_attr_mapper:map_attribute(fullName, IdPAttributes)
<rule>
can be a complex, nested term built from the following expressions:
"attrName"
— name of an attribute. If such a key is present in attributes received from IdP, the rule is expanded to its value. Here is an example:
id => {required, "id"}
emails => {optional, "mail"}
{keyValue, "attrName"}
— similar to the"attrName"
rule, but the result will contain both the attribute key and value as a JSON object. Here is an example:
custom => {optional, {keyValue, "schacHomeOrganization"}}
% would set user's custom value to
{"custom": {"schacHomeOrganization": "orgName"}}
% instead of just
{"custom": "orgName"}
{keyValue, "keyName", <rule>}
— similar to the{keyValue, "attrName"}
, but<rule>
can expand to any value, and the key in the result JSON can be specified explicitly. Here is an example:
custom => {optional, {keyValue, "organization", "schacHomeOrganization"}}
% would set user's custom value to:
{"custom": {"organization": "orgName"}}
{str, "literal"}
— the rule will be expanded to the literal string. Here is an example:
fullName => {required, {str, "John Doe"}}
% would make all users have the same fullName; `"John Doe"
{str_list, ["str1", "str2"]}
— the rule will be expanded to a list of literal strings. Here is an example:
entitlements => {required, {str_list, ["group1", "group2, "group3"]}}
% would make all users have the same three entitlements
{nested, ["key1", "key2", {list, "key3"}]}
— the rule will be expanded to a value nested in a JSON. The special expression{list, key}
can be used to parse a list of JSON objects, where each object has a specific key. Here is an example:
emails => {nested, ["emails", {list, "email"}]}
% would parse the following JSON:
{"emails": [
{"email": "abc@example.com", "verified": true},
{"email": "def@example.com", "verified": false}
]}
% into the following list of emails:
["abc@example.com", "def@example.com"]
{replace, "regex", "replacement", <rule>}
— this rule replaces matching substrings with the specified replacement.<rule>
can expand to a string or a list of strings, in which case the operation will be repeated on each string. The implementation uses Erlang'sre:replace/4
function, so the regular expressions and replacements must be built according to Erlang's regex format, which differs slightly from other formats. Here is an example:
fullName => {replace, "(.*) (.*) (.*)", "\\1 \\3", "fullName"}
% would change all 3-part names to 2-part, leaving out the middle one
% (e.g. John II Doe -> John Doe). Unmatched strings are not modified.
{concat, [<ruleA>, <ruleB>, ...]}
— concatenates a list of strings into one string, one by one:((<ruleA> + <ruleB>) + <ruleC>) + <ruleD> ...
. Every<rule>
must expand to a string or a list of strings. If a single string is concatenated with a list, it is concatenated with every element of the list. If two lists are concatenated, the elements are concatenated in pairs, creating a new list. If any of the lists is shorter, it is padded with empty strings. Examine possible combinations:
{concat, []} ->
undefined
{concat, [{str, "a"}]} ->
"a"
{concat, [{str, "a"}, {str, "b"}]} ->
"ab"
{concat, [{str, "a"}, {str_list, ["1", "2", "3"]}]} ->
["a1", "a2", "a3"]
{concat, [{str_list, ["a", "b", "c"]}, {str, "1"}]} ->
["a1", "b1", "c1"]
{concat, [{str_list, ["a", "b", "c"]}, {str_list, ["1", "2", "3"]}]} ->
["a1", "b2", "c3"]
{concat, [{str_list, ["a", "b", "c", "d"]}, {str_list, ["1", "2"]}]} ->
["a1", "b2", "c", "d"]
Example:
{entitlements => {concat, [{str, "group:"}, "groups"]}
% would prefix every user's entitlement with "group:"
{join, "<string>", <rule>}
— joins a list of strings with givenstring
.<rule>
must expand to a list of strings, or a single string (in which case the join just returns the unchanged string). Here is an example:
{join, " ", "nameTokens"}
% would parse the following JSON:
{"nameTokens": ["John", "Doe", "Junior"]}
% into the following fullName:
"John Doe Junior"
{split, "<string>", <rule>}
— splits a string into a list of strings on givenstring
.<rule>
must expand to a string or a list of strings in which case the results of splitting every string will be appended in one result list. Here is an example:
{entitlements => {optional, {split, ",", "groups"}}
% would parse the following JSON:
{"groups": "group1,team2,role3"}
% into the following list of entitlements:
["group1", "team2", "role3"]
% or the following JSON:
{"groups": ["group1,group2", "team3,team4"]}
% into the following list of entitlements:
["group1", "group2", "team3", "team4"]
{append, [<ruleA>, <ruleB>, ...]}
— appends lists or JSON objects together. Every<rule>
must expand to a string, list, or JSON. Examine possible combinations:
{append, []} ->
[]
{append, [{str, "a"}]} ->
["a"]
{append, [{str, "a"}, {str_list, ["c", "d"]}]} ->
["a", "c", "d"]
{append, [{str_list, ["a", "b"]}, {str_list, ["c", "d"]}]} ->
["a", "b", "c", "d"]
{append, [{keyValue, "groups"}, {keyValue, "teams"}]} ->
{"groups": [...], "teams": [...]}
Example:
{custom => {append, [{keyValue, "organization"}, "customAttrs"]}
% provided that "customAttrs" is a nested JSON, would give something like:
{"organization": "my-org", "cusAttr1": "val1", "cusAttr2": "val2"}
{filter, "<regex>", <rule>}
— filters a list, leaving only the strings that match the<regex>
.<rule>
must expand to a list of strings, or a string, in which case it will be treated as a list with one element. Here is an example:
{emails => {filter, ".*@gmail.com", "emails"}
% would leave only the emails from gmail.com
{any, [<ruleA>, <ruleB>, ...]}
— tries all rules one by one until any of them gives a valid result. In case all of them fail, returns theundefined
value. Here is an example:
{fullName => {optional, {any, [{concat, [{str, "John "}, "surName"]}, "userName"]}}
% would set all users' names to:
% a) "John <surName>" if the attribute "surName" was found
% b) "<userName>" if the attribute "userName" was found
% c) undefined (displayed in GUI as "Unnamed User") if none of the attributes
% was found (if 'optional' was changed to 'required', the login would fail).
The following example, which uses all possible rules:
click to expand
attributeMapping => #{
subjectId => {required, {replace, "c", "x", "id"}},
fullName => {optional, {any, ["fullName", {join, " ", "nameTokens"}]}},
username => undefined,
emails => {required, {filter, ".*@my.org", {split, ",", "emails"}}},
entitlements => {optional, {concat, [
{str_list, ["a", "b", "c", "d"]},
{str, ":"},
"groups",
{str, "/"},
{str_list, ["1", "2", "3", "4"]}
]}},
custom => {optional, {append, [
"customAttrs",
{keyValue, "organization"},
{keyValue, "roles", {nested, ["roles", {list, "role"}, "displayName"]}}
]}}
}
would parse the following JSON:
click to expand
{
"id": "abcdef1c2c3c4c",
"nameTokens": ["John", "Doe", "Jr"],
"username": "jodoe",
"emails": "joedoe@example.com,john.doe@my.org",
"groups": ["some", "entitlement", "from", "idp"],
"roles": [
{"role": {
"displayName": "role1"
}},
{"role": {
"displayName": "role2"
}},
{"role": {
"displayName": "role3"
}}],
"organization": "My Organization",
"customAttrs": {
"thirdAttr": {
"nested": "json"
},
"secondAttr": ["second", "value"],
"fourthAttr": 17,
"firstAttr": "firstValue"
}
}
into the following Onedata user attributes:
click to expand
{
"idp": "my-idp",
"subjectId": "abxdef1x2x3x4x",
"fullName": "John Doe Jr",
"username": null,
"emails": ["john.doe@my.org"],
"entitlements": ["a:some/1", "b:entitlement/2", "c:from/3", "d:idp/4"],
"custom": {
"firstAttr": "firstValue",
"secondAttr": ["second", "value"],
"fourthAttr": 17,
"thirdAttr": {
"nested": "json"
},
"organization": "My Organization",
"roles": ["role1", "role2", "role3"]
}
}
# Attribute mapping inheritance
If attribute mapping is specified in defaultProtocolConfig
, it will be inherited
by all IdPs using that protocol (openid
or saml
) — just like all other
attributes. It is possible to override each key in the IdP config. For example,
the following config (default and IdP specific):
defaultProtocolConfig => #{
attributeMapping => #{
subjectId => {required, "eduPersonUniqueID"},
fullName => {required, ["displayName", "surName"]},
username => {optional, "eduPersonPrincipalName"},
emails => {optional, "mail"}
}
}
...
{my_idp, #{
protocolConfig => #{
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
% if not explicitly set to undefined, login rules will be
% inherited from defaultProtocolConfig!
username => undefined,
entitlements => {optional, "groups"}
}
}
}
is equivalent to the following config for the given IdP:
{my_idp, #{
protocolConfig => #{
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {required, ["displayName", "surName"]},
username => undefined,
emails => {optional, "mail"},
entitlements => {optional, "groups"}
}
}
}
# Exemplary IdP attributes
Bear in mind that typical attributes received via OpenID and SAML are different. They differ depending on the IdP — refer to their documentation to correctly build attribute mapping rules. Nevertheless, there is a certain set of universally used attributes. The below examples use fairly common attributes:
OpenID attributes example (EGI Check-In)
{
"sub": "12345678-1234-1234-1234-12345678",
"preferred_username": "johndoe",
"name": "John Doe",
"eduperson_entitlement": [
"urn:mace:egi.eu:group:group1#sso.egi.eu",
"urn:mace:egi.eu:group:group2#sso.egi.eu",
"urn:mace:egi.eu:group:registry:nested-group:role=member#aai.egi.eu",
],
"given_name": "John",
"family_name": "Doe",
"email_verified": true,
"email": "john.doe@google.com"
}
SAML attributes example (Elixir Europe)
{
"eduPersonUniqueId": "1234567890@elixir-europe.org",
"displayName": "John Doe",
"eduPersonPrincipalName": "johndoe@elixir-europe.org",
"mail": "john.doe@gmail.com",
"eduPersonEntitlement": [
"elixir_test:members",
"elixir_test:OneData",
"elixir_test:OneData:subgroup-1",
"elixir_test:OneData:subgroup-1:subgroup-2"
],
"https://login.elixir-europe.org/attribute-definition/forwardedScopedAffiliation/v1": "affiliate@elixir-europe.org",
"schacHomeOrganization": "google.com"
}
NOTE
Although the SAML attributes are received in SAML assertions in the XML format, they are internally converted to JSON and treated analogically to OpenID attributes during attribute mapping.
SAML specification defines a certain set of attributes that can be served by IdPs. Onezone
recognizes the most commonly used ones — see the table below. It presents the attribute
type identifiers and their human-readable aliases used in Onezone. All received attributes
with the below identifiers will be translated to corresponding aliases, and you must use
the aliases in attribute mapping rules. Of course, the IdP might send attributes that are
not listed in the below table or are completely customary for the considered organization.
Then, in your attribute mapping rules, use the literal type identifiers that appear in the
assertion XML. They might be custom strings, usually starting with urn:oid:
or URIs (as
in the above example for Elixir) — refer to the IdP's documentation.
alias | SAML attribute type identifier |
---|---|
"uid" | urn:oid:0.9.2342.19200300.100.1.1 |
"displayName" | urn:oid:2.16.840.1.113730.3.1.241 |
"givenName" | urn:oid:2.5.4.42 |
"commonName" | urn:oid:2.5.4.3 |
"surName" | urn:oid:2.5.4.4 |
"mail" | urn:oid:0.9.2342.19200300.100.1.3 |
"eduPersonTargetedID" | urn:oid:1.3.6.1.4.1.5923.1.1.1.10 |
"eduPersonUniqueID" | urn:oid:1.3.6.1.4.1.5923.1.1.1.13 |
"eduPersonPrincipalName" | urn:oid:1.3.6.1.4.1.5923.1.1.1.6 |
"eduPersonScopedAffiliation" | urn:oid:1.3.6.1.4.1.5923.1.1.1.9 |
"eduPersonEntitlement" | urn:oid:1.3.6.1.4.1.5923.1.1.1.7 |
"schacHomeOrganization" | urn:oid:1.3.6.1.4.1.25178.1.2.9 |
"telephoneNumber" | urn:oid:2.5.4.20 |
"organizationName" | urn:oid:2.5.4.10 |
"organizationalUnitName" | urn:oid:2.5.4.11 |
"employeeNumber" | urn:oid:2.16.840.1.113730.3.1.3 |
"employeeType" | urn:oid:2.16.840.1.113730.3.1.4 |
Exemplary attribute mapping using known and custom SAML attributes:
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, {any, ["displayName", {concat, ["givenName", {str, " "}, "surName"]}]}},
username => {optional, "eduPersonPrincipalName"},
% Custom attribute type as a string
email => {optional, "idp-custom-attribute"},
% Custom attribute type in form of urn:oid:xxx
entitlements => {optional, "urn:oid:9.9.9.9.9"},
% Custom attribute type in form of an URI
custom => {required, "https://login.elixir-europe.org/attribute-definition/forwardedScopedAffiliation/v1"}
}
# Entitlement Mapping
Entitlement mapping is used to automatically map users entitlements in an IdP to group memberships in Onedata. Entitlements can be understood as the right to be a member of a group (or, possibly, a group structure) with certain privileges.
For each entitlement, a group is created in Onedata that mirrors the group in the IdP, together with hierarchical relations (nested groups). They are created gradually at every user login, which causes reconciliation of all his entitlements, but only them (Onedata is not aware of the other groups from the IdP, unless they come with another user login). Hence, typically, Onedata holds a subset of all groups originating from an IdP.
All IdP-related groups in Onedata are protected — they cannot be deleted or modified, and their membership or privileges in other protected groups cannot be changed. They can however be added to non-IdP groups and vice-versa, as well as other resources in Onedata. Users can be added manually to the IdP-related groups.
The section in auth.config concerning the Entitlement Mapping has the following structure (example):
entitlementMapping => #{
enabled => true,
voGroupName => "my-organization",
adminGroup => "all_users:admins",
parser => nested_entitlement_parser,
parserConfig => #{
topGroupType => unit,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => member
}
}
enabled
— enable or disable entitlement mapping for the given IdP.voGroupName
— if specified, a special VO group will be created and all groups originating from the given IdP will be added as members (subgroups) to it. Note that if an entitlement overlaps with thevoGroupName
, it will be considered the same as the VO group. See the below table for examples on how different entitlements would be mapped assuming that thevoGroupName
is set tomyVO
:
entitlement | group structure in Onedata |
---|---|
members | myVO/members |
myVO | myVO |
myVO/members | myVO/members |
users/admins | myVO/users/admins |
adminGroup
— (formerly known as Super Group) if specified, it defines an Admin Group for the given IdP. TheadminGroup
should be an existing entitlement, formatted in the same way as the output of your entitlement mapping rules (refer to the example below). The Admin Group will be granted admin privileges to all groups originating from the specified IdP. Consequently, all members of the Admin Group will inherit admin privileges for all groups from that IdP. For example, if there is"admins"
group in an IdP, and it is specified as theadminGroup
, users of the original"admins"
group will be mapped to the Onedata"admins"
group. Hence, they will automatically acquire admin privileges in the groups associated with the IdP.parser
&parserConfig
— see below.
# Entitlement parsers
Entitlement parsers are used to convert user entitlements from an IdP to group memberships in Onedata. Two predefined parsers can handle the majority of common use cases:
flat_idp_group_parser
— converts every entitlement into a single group membership in Onedata. Each created group has a configured group type (groupType
) and the user with the corresponding entitlement is added to the group with a specified set of privileges (userPrivileges
). The name of the group is derived from the entitlement but normalized to comply with allowed chars. If the IdP has a specifiedvoGroupName
, the group will be added as a subgroup with the designated set of privileges (groupPrivilegesInVo
). However, if thevoGroupName
is not specified this parameter has no effect.
Consider the following entitlementMapping
config:
entitlementMapping => #{
enabled => true,
voGroupName => "my-organization",
adminGroup => undefined,
parser => flat_entitlement_parser,
parserConfig => #{
groupType => team,
groupPrivilegesInVo => member,
userPrivileges => manager
}
}
Suppose that the following JSON is received from the IdP:
{
"groups": ["developers", "admins"],
...
}
The attribute mapping rules are:
attributeMapping => #{
entitlements => {optional, "groups"},
...
}
Then, the following group structure would be created after the user logs in:
my-organization [organization]
u u
(member privs>| |<member privs)
| |
[team] developers admins [team]
u u
(manager privs>\ /<manager privs)
\ /
<user>
nested_entitlement_parser
— converts every entitlement into a chain of nested groups in Onedata by splitting the input using the specifiedsplitWith
string. The created groups have configured type (topGroupType
,subGroupsType
), based on their position in the structure. The user with the corresponding entitlement is added only to the bottom group with the provided set of privileges (userPrivileges
). The names of the groups are derived from the splitting of the entitlement, but normalized to comply with allowed chars. If the IdP has a specifiedvoGroupName
, the top group will be added as a subgroup to it with the designated set of privileges (topGroupPrivilegesInVo
). All nested groups will have the type ofsubGroupsType
and the set of privileges specified insubGroupsPrivilegesInParent
towards their parent group.
Consider the following entitlementMapping
config:
entitlementMapping => #{
enabled => true,
% Don't create a VO group, unlike in above
% flat_entitlement_parser example, but define adminGroup
voGroupName => undefined,
adminGroup => "all_users:admins",
parser => nested_entitlement_parser,
parserConfig => #{
splitWith => ":",
topGroupType => unit,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => manager
}
Suppose that the following JSON is received from the IdP:
{
"groups": [
"all_users:admins",
"all_users:cloud_users:vm_managers"
],
...
}
The attribute mapping rules are:
attributeMapping => #{
entitlements => {optional, "groups"},
...
}
Then, the following group structure would be created after the user logs in:
all_users [unit]
u u
(admin privs>| \<member privs)
| \
.---------' cloud_users [team]
/ u u
\ (admin privs>/ \<member privs)
\ / \
\ .--' vm_managers [team]
'---. | u u
\ | (admin privs>/ /<manager privs)
\| / /
[team] admins------' /
u /
(manager privs>\ /
\ /
<user>
Note how the adminGroup
("all_users:admins"
) is added to all groups in the IdP
with admin privileges. The user will inherit all those privileges and will
effectively be an admin in all those groups.
# Group types
There are four group types in Onedata. Their purpose is to facilitate reflecting existing organizational hierarchies. Apart from the visual representation in GUI and intuitive meaning, the group type does not have a functional effect on the system usage. Their interpretation is up to the admins and users, but the recommended usage of the types is:
organization
— represents an organization; institution or virtual organization (VO), e.g."Elixir Europe"
unit
— represents a unit in the organization, e.g."R\&D department"
team
— represents a collaborating team of users with common goals, e.g."WP5.1"
role_holders
— groups people that possess a certain role, e.g."Admins"
(in Onedata, there is no concept of roles — rather than that, users with the same role/privileges should be organized into groups).
# Privileges in entitlements
It is possible to specify the privileges of the user towards the bottom group of the nested structure or the privileges of the groups in the nested chain toward their parents.
User privileges in the bottom group are reconciled upon every login. They can be changed manually, but the changes will be overwritten during a consecutive login. Example:
- User logs in with entitlement
"developers"
and"manager"
privileges. - User is manually granted
"admin"
privileges in the"developers"
group. - User logs in again with
"developers:member"
, which causes his privileges to be changed down to"member"
— manual changes have been overwritten.
For child groups in the hierarchy, the privileges are reconciled every time a user with given group logs in. They cannot be changed manually as the groups are protected.
There are four possible sets of privileges: none
, member
, manager
, admin
.
They expand to a certain set of Onedata group privileges:
none →
[]
member →
[group_view]
manager →
[group_add_atm_inventory,group_add_child, group_add_harvester,group_add_parent,group_add_user, group_leave_parent,group_remove_atm_inventory, group_remove_child,group_remove_harvester,group_remove_user, group_view,group_view_privileges]
admin →
[group_add_atm_inventory,group_add_child,group_add_cluster, group_add_harvester,group_add_parent,group_add_space, group_add_user,group_create_handle, group_create_handle_service,group_delete, group_leave_cluster,group_leave_handle, group_leave_handle_service,group_leave_parent, group_leave_space,group_remove_atm_inventory, group_remove_child,group_remove_harvester,group_remove_user, group_set_privileges,group_update,group_view, group_view_privileges]
# Custom entitlement parsers (advanced)
Entitlement parsers are Erlang modules that implement
entitlement_parser_behaviour
. They are used to convert a raw entitlement
coming from an IdP into Onedata's internal, unified format, which looks like
this:
#idp_entitlement{
idp = myIdP,
path = [
#idp_group{type = organization, name = <<"my-org">>, privileges = member},
#idp_group{type = unit, name = <<"my-unit">>, privileges = member},
#idp_group{type = team, name = <<"my-team">>, privileges = manager}
],
% user privileges in the bottom group
privileges = admin
}
Such an entitlement expresses that a chain of nested groups should be created, and the user should be added to the bottom group with the specified set of privileges. Each entry in the path denotes the type and name of the group in Onedata, as well as the privileges of that group in its parent group (if it exists). The above entitlement would result in the following group structure in Onezone:
my-organization [organization]
u
|<member privs)
|
my-unit [unit]
u
|<manager privs)
|
my-team [team]
u
|<admin privs)
|
<user>
If the adminGroup
is specified for myIdP
, let's call it "admins"
, and
the user has the following entitlements (after the mapping):
[
#idp_entitlement{
idp = myIdP,
path = [
#idp_group{type = organization, name = <<"my-org">>, privileges = member},
#idp_group{type = unit, name = <<"my-unit">>, privileges = member},
#idp_group{type = team, name = <<"my-team">>, privileges = manager}
],
% user privileges in the bottom group
privileges = admin
},
#idp_entitlement{
path = [
#idp_group{type = organization, name = <<"my-org">>, privileges = member},
#idp_group{type = role_holder, name = <<"admins">>, privileges = <irrelevant>}
],
privileges = manager
}
]
Then, the following group structure would be created:
my-organization [organization]
u u
| |<member privs)
.---------' |
(admin privs>| my-unit [unit]
| u u
| .-----------' |<manager privs)
| | |
| |<admin privs) my-team [team]
| | u u
| | (admin privs>| |<admin privs)
| | | |
[role_holder] admins-------------' |
u |
(manager privs>| |
'----------------- <user>
Furthermore, if voGroupName
is specified as "my-vo-group"
, the whole
structure is added as children to that VO (organization) group. In such case,
the above entitlements would result in the following group structure:
my-vo-group [organization]
u u
(admin privs>| |<member privs)
| |
.------' '---------------my-organization [organization]
| u u
| | |<member privs)
| .---------' |
| (admin privs>| my-unit [unit]
| | u u
| | .-----------' |<manager privs)
| | | |
| | |<admin privs) my-team [team]
| | | u u
'--------------. | | (admin privs>| |<admin privs)
\| | | |
[role_holder] admins--------------' |
u |
(manager privs>| |
'----------------- <user>
To implement your custom entitlement parser, see the entitlement parser section.
# Auth plugins
Auth plugins are user-defined Erlang modules that can be injected into the
Onezone service and used to customize the OIDC / SAML sign-on procedure. All plugins
must be Erlang files with .erl
extension which are expected to be found in the
plugin directory /var/lib/oz_worker/plugins
.
The plugins are loaded upon Onezone startup. When using a deployment with more than one node, the same plugins must be provisioned on all nodes.
NOTE
If you wish to implement your own auth plugin, we recommend contacting us (opens new window) to make the process as smooth as possible.
Plugins must conform to the predefined API that is specified in Erlang behavior modules. Refer to the oz-worker source code (opens new window) for the behaviors and implementation guide.
Each plugin must implement the onezone_plugin_behaviour
, which has one
callback — type/0
, that returns the type of the plugin:
attribute_mapper | entitlement_parser | openid_plugin
.
TIP
See the corresponding behaviors for more info;
entitlement_parser
and attribute_mapper
support validation examples are
evaluated upon startup and the results are logged in Onezone logs.
# Attribute mapper
This auth plugin maps IdP attributes into Onedata attributes. It must implement the
onezone_plugin_behaviour
that returns the attribute_mapper
atom from the type/0
callback and the attribute_mapper_behaviour
. Refer to the oz-worker source code (opens new window)
for the behavior module and implementation details. An exemplary custom attribute mapper
(custom_attribute_mapper.erl
) can be found in the plugin directory (opens new window).
# Entitlement parser
This auth plugin maps IdP entitlements into Onedata entitlements (group memberships). It
must implement the onezone_plugin_behaviour
that returns the entitlement_parser
atom
from the type/0
callback and the entitlement_parser_behaviour
. Refer to the
oz-worker source code (opens new window) for the behavior module and implementation details. An
exemplary custom entitlement parser that supports the EGI group format
(custom_entitlement_parser.erl
) can be found in the plugin directory (opens new window).
# OpenID plugin
This auth plugin handles the Open ID login process. It must implement the
onezone_plugin_behaviour
that returns the openid_plugin
atom from the type/0
callback and the openid_plugin_behaviour
. Refer to the
oz-worker source code (opens new window) for the
behavior module and implementation details.
# Troubleshooting
In case of problems, this checklist might be useful:
Make sure that you have correctly placed or overwritten the
auth.config
file. Go to the Onezone node and examine/etc/oz_worker/auth.config
. Especially in docker-based deployments, changes made on the host may not be reflected properly in the container.Wait for the
auth.config
to be reloaded — the config is cached for 60 seconds, and any changes you introduce might take up to this time to be visible. For easier testing with frequent changes, consider using the test login page.If any error occurs during the login process, see what page you are currently on:
The IdP page — either your
auth.config
has errors (the error on the IdP page should indicate the reason), or the issue is on the IdP side. In any case, try contacting the administrators, who can examine their logs and give you hints on the reason.The Onezone GUI — see the image below. The error page will contain basic information about the error. If that is not enough to identify the problem, copy the request state identifier from the error page and check the logs — see the next point.
- Check Onezone logs for any hints of what might have gone wrong:
Errors in
auth.config
are logged on thealert
log level, they should give clear information on how to fix the config.Erroneous requests are logged on different log levels, depending on the error severity. They always include the request state identifier (see the image above), so they are easy to look up.
Some errors with low severity are logged on the
debug
log level, which is disabled by default. If needed, you can turn on thedebug
logs (keep in mind that they have a negative impact on the system performance). After doing so, go through the login process again and take the request state identifier. You will get detailed logs from the whole login process — look them up using the state identifier. Remember to turn off the debug logs when you are finished.
# LUMA Integration
The attributes and entitlements collected from IdPs can be very useful for mapping storage
users to Onedata users — see the Local User Mapping (LUMA) docs. When a
provider requests LUMA to resolve storage credentials such as uid
and gid
, it includes
the attributes collected from IdPs. These attributes can be utilized to differentiate and
identify the storage users effectively.
# Custom icon guidelines
To use your custom icon on the login page, place it on the Onezone host under the
path /var/www/html/oz_worker/custom/<path>
and reference it in the config like
this: iconPath => "/custom/<path>"
. If you are using docker-compose, simply
mount your icon by adding a volume, for example:
# docker-compose.yaml
...
volumes:
— "/path/to/your/icon.svg:/var/www/html/oz_worker/custom/my-icon.svg"
...
----------------------------------------------
# test.auth.config
...
iconPath => "/custom/my-icon.svg",
...
Please follow the guidelines below for the best visual effects:
- The preferred image format is vector graphics in SVG.
- Avoid raster (bitmap) graphics embedded in an SVG — some browsers (e.g. Firefox) do not handle them well.
- If you don't have an SVG version, PNG with transparency is preferred over JPG.
- It's best if your icon is placed on a square canvas (see the image below).
- The canvas should be transparent, in such case
iconBackground
color will be visible underneath. You can use a custom background, but make sure you fill the entire canvas with it and make it a perfect square, otherwise the background color might show through. - In the case of a bitmap image (PNG, JPG), the canvas size should be 50×50 pixels or any multiple of it. Consider the size of 200×200 pixels for good quality on retina displays.
- The icon canvas takes up the whole space on the login button. It means that there are no automatic margins — you should introduce the desired margins on the canvas (see the image below).
- Make sure to center your icon on the image canvas (unless, of course, you want it to be asymmetric).
# Test login page
It is possible to test your auth.config
using the
test login page without interrupting the Onezone service. It also serves as a
way to diagnose problems during integration with IdPs, including attribute or
entitlement mapping. To use the test login page, place your auth.config
on the
Onezone host under the path /etc/oz_worker/test.auth.config
. The test config
coexists with the production /etc/oz_worker/auth.config
with no interference.
It is not cached at all, so you can introduce changes while the Onezone
service is online and verify the results immediately. To go through the test
login process, go to https://onezone.example.com/#/test/login
. You will see
the IdPs that are specified in your test.auth.config
and an indication that
this is a test login page (see the first image below). By choosing one of the
IdPs, you will go through a simulation of the login process and receive a
summary at the end (see the second image below). While it uses the standard flow
in the IdP, on the Onezone side no users or groups (resulting from entitlements)
are created in the process. The summary expresses what information would be
gathered if it were a login flow in production, and includes detailed logs from the
whole login process.
TIP
The SAML SP metadata XML based on the test.auth.config
can be viewed under the
following URL: https://onezone.example.com/saml/sp.xml?test=true
# Complete example
A complete exemplary auth.config
file is presented below. It can also be found
on your Onezone node under /etc/oz_worker/template.auth.config
.
click to expand
#{
version => 3,
% Allows to log in to Onezone using username & password.
basicAuthConfig => #{
enabled => true
},
openidConfig => #{
% Enable OpenID login protocol — if disabled, all OpenID IdPs will be
% hidden from the login page.
enabled => true,
% Default config for every OpenID IdP, can be overridden in IdP config
defaultProtocolConfig => #{
% Internal plugin that will be used for handling the login process -
% if the IdP uses standard OpenID Connect protocol,
% default_oidc_plugin is the way to go. If not, IdP specific plugin
% can be implemented and specified here.
plugin => default_oidc_plugin,
% Config specific for default_oidc_plugin
pluginConfig => #{
% Scope requested from OpenID Connect IdP
scope => "openid email profile",
% HTTP method used to exchange auth code for an access token: post | get
accessTokenAcquireMethod => post,
% How the client secret should be sent to the IdP: urlencoded | inAuthHeader
clientSecretPassMethod => urlencoded,
% How user's access token should be sent to the IdP: urlencoded | inAuthHeader
accessTokenPassMethod => inAuthHeader,
% Allows to augment requests with additional data
customData => #{
% Additional data for access_token endpoint request
accessToken => #{
% query string or post body parameters (key-value)
parameters => undefined,
% headers (key-value)
headers => undefined
},
% Additional data for userinfo endpoint request
userInfo => #{
parameters => undefined,
headers => undefined
}
}
},
% Enables/disables authorization using access tokens from the IdP
% Supported only in OpenID protocol
authorityDelegation => #{
% Enabled for this IdP
enabled => true
% The tokenPrefix attribute defines a prefix used to distinguish
% tokens from given IdP. It defaults to "<idp>:", where <idp> is
% the identifier used in config. Can be overriden in IdP config,
% like the following:
% tokenPrefix => "my-idp/"
% Exemplary token usage with with such config:
% curl -H "X-Auth-Token: my-idp/lkj9s87rf1234SDfh6721hqd7991" ...
},
% Defines how the attributes from OpenID user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% OpenID attributes.
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => {optional, "groups"},
custom => {optional, "name"}
},
% Rules for mapping entitlements in the IdP into entitlements in Onedata.
entitlementMapping => #{
enabled => false
}
}
},
samlConfig => #{
% Enable SAML login protocol — if disabled, all SAML IdPs will be hidden
% from the login page and the endpoint serving SAML metadata will be
% disabled.
enabled => true,
% Information used to build SAML SP metadata XML, refer to SAML
% documentation for details on below attributes.
spConfig => #{
entityId => "https://onezone.example.com/sp",
certFile => "/etc/oz_worker/certs/saml_cert.pem",
keyFile => "/etc/oz_worker/certs/saml_key.pem",
organizationName => "My organization",
organizationDisplayName => "My organization",
techContactName => "John Doe",
techContactEmail => "john.doe@onezone.example.com",
% Should the metadata be signed with keyFile
signMetadata => false,
% Should the Auth Requests be signed with keyFile
signRequests => true,
% Should Onezone request signed assertions
wantAssertionsSigned => true
},
% Default config for every SAML IdP, can be overridden in IdP config
defaultProtocolConfig => #{
% SSO binding — defines what type of request should be performed
% to redirect the user to the IdP's login page. Possible values:
% http_redirect (default) or http_post
preferredSsoBinding => http_redirect,
% Defines how the attributes from SAML user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% SAML attributes.
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {required, {any, ["displayName", "surName"]}},
username => {optional, "eduPersonPrincipalName"},
emails => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => {optional, "eduPersonScopedAffiliation"}
},
% Rules for mapping entitlements in IdP into entitlements in Onedata.
entitlementMapping => #{
% Enable / disable entitlement mapping for given IdP
enabled => true,
% The name of the parent group to which all groups from this IdP
% will belong (reflecting a Virtual Organization)
voGroupName => undefined,
% A special group that has admin rights to all groups from this
% IdP.
adminGroup => undefined,
% Erlang module (plugin) that will be used to parse user's
% entitlements from this IdP
parser => nested_entitlement_parser,
% Config specific for the nested_entitlement_parser
parserConfig => #{
splitWith => "/",
topGroupType => unit,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => member
}
}
}
},
supportedIdps => [
% basicAuth is a special IdP id reserved for signing in with username & password
% and the only valid config entry using the basicAuth protocol.
{basicAuth, #{
% Configuration of the login page button
displayName => "username & password",
% Some predefined icons are built-in into the GUI app.
% Their paths start with /assets/images/auth-providers.
% For a custom icon, put it in:
% /var/www/html/oz_worker/custom/<path>
% and reference it here like this: /custom/<path>
iconPath => "/assets/images/auth-providers/basicauth.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any).
iconBackgroundColor => "#4BD187",
% Which protocol is used for this IdP — basicAuth is the only
% valid one for basicAuth IdP.
protocol => basicAuth
}},
{google, #{
% Configuration of the login page button
displayName => "Google",
% Some predefined icons are built-in into the GUI app.
% Their paths start with /assets/images/auth-providers.
% For a custom icon, put it in:
% /var/www/html/oz_worker/custom/<path>
% and reference it here like this: /custom/<path>
iconPath => "/assets/images/auth-providers/google.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any).
iconBackgroundColor => "#F1514F",
% Which protocol is used for this IdP
protocol => openid,
% Configuration specific for OpenID protocol — overrides the default
protocolConfig => #{
% Internal plugin that will be used for handling the login process -
% if the IdP uses standard OpenID Connect protocol,
% default_oidc_plugin is the way to go. If not, IdP specific plugin
% can be implemented and specified here.
plugin => default_oidc_plugin,
% Config specific for default_oidc_plugin
pluginConfig => #{
% Client Id and secret acquired during registration
clientId => "****************************************************",
clientSecret => "****************************************************",
% Defines how to resolve OpenID endpoints
endpoints => #{
% The XRDS endpoint, will be used if referenced in below endpoints
xrds => "https://accounts.google.com/.well-known/openid-configuration",
% standard OIDC endpoints — literal URLs or tuples {xrds, "key"} -
% "key" will be extracted from the XRDS JSON.
authorize => {xrds, "authorization_endpoint"},
accessToken => {xrds, "token_endpoint"},
userInfo => {xrds, "userinfo_endpoint"}
},
% Scope requested from OpenID Connect IdP
scope => "openid email profile",
% HTTP method used to exchange auth code for an access token: post | get
accessTokenAcquireMethod => post,
% How the client secret should be sent to the IdP: urlencoded | inAuthHeader
clientSecretPassMethod => urlencoded,
% How user's access token should be sent to the IdP: urlencoded | inAuthHeader
accessTokenPassMethod => inAuthHeader,
% Allows to augment requests with additional data
customData => #{
% Additional data for access_token endpoint request
accessToken => #{
% query string or post body parameters (key-value)
parameters => #{"param1" => "val1"},
% headers (key-value)
headers => #{"header1" => "val1"}
},
% Additional data for userinfo endpoint request
userInfo => #{
parameters => #{"param2" => "val2"},
headers => #{"header2" => "val2"}
}
}
},
% Enables/disables authorization using access tokens from the IdP
% Supported only in OpenID protocol
authorityDelegation => #{
% Enabled for this IdP
enabled => true,
% The tokenPrefix attribute defines a prefix used to distinguish
% tokens from given IdP.
% Exemplary token usage with the below such config:
% curl -H "X-Auth-Token: google:lkj9s87rf1234SDfh6721hqd7991" ...
tokenPrefix => "google:"
},
% Defines how the attributes from OpenID user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% OpenID attributes.
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => {optional, "given_name"},
custom => {optional, "given_name"}
},
% Rules for mapping entitlements in the IdP into entitlements in Onedata.
entitlementMapping => #{
enabled => true,
% The name of the parent group to which all groups from this IdP
% will belong (reflecting a Virtual Organization)
voGroupName => undefined,
% A special group that has admin rights to all groups from this
% IdP.
adminGroup => undefined,
parser => flat_entitlement_parser,
parserConfig => #{
groupType => team,
groupPrivilegesInVo => member,
userPrivileges => member
}
}
}
}},
{elixir, #{
% Configuration of the login page button
displayName => "Elixir",
% To use the icon like below, put it in:
% /var/www/html/oz_worker/custom/images/elixir.svg
iconPath => "/custom/images/elixir.svg",
% Background color is useful for icons with transparency. Moreover,
% after selecting an IdP, its icon disappears and a spinner is
% shown — hence background color should be kept the same as icon's
% background color (if any).
iconBackgroundColor => "#FF7A04",
% Which protocol is used for this IdP
protocol => saml,
% Configuration specific for SAML protocol — overrides the default
protocolConfig => #{
% URL pointing to IdP SAML metadata XML
metadataUrl => "https://login.elixir-czech.org/proxy/saml2/idp/metadata.php",
% SSO binding — defines what type of request should be performed
% to redirect the user to the IdP's login page. Possible values:
% http_redirect (default) or http_post
preferredSsoBinding => http_redirect,
% Defines how the attributes from SAML user info should be mapped
% to Onedata user attributes. Attributes must correspond to existing
% SAML attributes.
attributeMapping => #{
subjectId => {required, "eduPersonUniqueId"},
fullName => {required, "displayName"},
username => {optional, "eduPersonPrincipalName"},
emails => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => {optional, "eduPersonScopedAffiliation"}
},
% Rules for mapping entitlements in IdP into entitlements in Onedata.
entitlementMapping => #{
% Enable / disable entitlement mapping for given IdP
enabled => true,
% The name of the parent group to which all groups from this IdP
% will belong (reflecting a Virtual Organization)
voGroupName => "Elixir",
% A special group that has admin rights to all groups from this
% IdP.
adminGroup => "elixir_test:tsi-admin",
% Erlang module (plugin) that will be used to parse user's
% entitlements from this IdP
parser => nested_entitlement_parser,
% Config specific for the nested_entitlement_parser
parserConfig => #{
splitWith => ":",
topGroupType => unit,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => member
}
}
}
}}
]
}.
# Minimal config
Minimal config that enables only basic auth (username & password login) — included by default in Onezone installation.
#{
version => 3,
basicAuthConfig => #{
enabled => true
},
samlConfig => #{
enabled => false
},
openidConfig => #{
enabled => false
},
supportedIdps => [
{basicAuth, #{
displayName => "username & password",
iconPath => "/assets/images/auth-providers/basicauth.svg",
iconBackgroundColor => "#4BD187",
protocol => basicAuth
}}
]
}.
# Exemplary entries for selected IdPs
Below are some working config examples that use predefined icons, to be placed
in the supportedIdps
section of the config. In the case of OpenID IdPs, it is
required to insert the Client ID and Secret in the config.
# Username & password login
click to expand
{basicAuth, #{
displayName => "username & password",
iconPath => "/assets/images/auth-providers/basicauth.svg",
iconBackgroundColor => "#4BD187",
protocol => basicAuth
}}
# KeyCloak config (OpenID Connect)
click to expand
{keycloakIdP, #{
displayName => "RHEA KeyCloak",
iconPath => "/assets/images/auth-providers/rhea.svg",
iconBackgroundColor => "#B51017",
protocol => openid,
protocolConfig => #{
plugin => default_oidc_plugin,
pluginConfig => #{
clientId => "****************************************************",
clientSecret => "****************************************************",
endpoints => #{
xrds => "https://fed-id.nuv.la/auth/realms/SixSq/.well-known/openid-configuration",
authorize => {xrds, "authorization_endpoint"},
accessToken => {xrds, "token_endpoint"},
userInfo => {xrds, "userinfo_endpoint"}
},
scope => "openid email profile",
accessTokenAcquireMethod => post,
clientSecretPassMethod => urlencoded,
accessTokenPassMethod => inAuthHeader,
customData => #{}
},
authorityDelegation => #{
enabled => true,
tokenPrefix => "keycloakIdP:"
},
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => {optional, {append, ["groups", "roles"]}},
custom => {optional, "given_name"}
},
entitlementMapping => #{
enabled => true,
voGroupName => "Keycloak IdP",
adminGroup => undefined,
parser => nested_entitlement_parser,
parserConfig => #{
splitWith => "/",
topGroupType => team,
topGroupPrivilegesInVo => member,
subGroupsType => team,
subGroupsPrivilegesInParent => member,
userPrivileges => member
}
}
}
}}
# GitHub config (OpenID Connect)
click to expand
{github, #{
displayName => "Github",
iconPath => "/assets/images/auth-providers/github.svg",
iconBackgroundColor => "#1E2325",
protocol => openid,
protocolConfig => #{
plugin => default_oidc_plugin,
pluginConfig => #{
clientId => "****************************************************",
clientSecret => "****************************************************",
endpoints => #{
authorize => "https://github.com/login/oauth/authorize",
accessToken => "https://github.com/login/oauth/access_token",
userInfo => [
"https://api.github.com/user",
{"emails", "https://api.github.com/user/emails"}
]
},
scope => "user,user:email",
accessTokenAcquireMethod => post,
clientSecretPassMethod => urlencoded,
accessTokenPassMethod => urlencoded,
customData => #{
userInfo => #{
headers => #{
"User-Agent" => "Onedata"
}
}
}
},
authorityDelegation => #{
enabled => true,
tokenPrefix => "github:"
},
attributeMapping => #{
subjectId => {required, "id"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, {nested, ["emails", {list, "email"}]}},
entitlements => undefined,
custom => undefined
},
entitlementMapping => #{
enabled => false
}
}
}}
# Google config (OpenID Connect)
click to expand
{google, #{
displayName => "Google",
iconPath => "/assets/images/auth-providers/google.svg",
iconBackgroundColor => "#FFFFFF",
protocol => openid,
protocolConfig => #{
plugin => default_oidc_plugin,
pluginConfig => #{
clientId => "****************************************************",
clientSecret => "****************************************************",
endpoints => #{
xrds => "https://accounts.google.com/.well-known/openid-configuration",
authorize => {xrds, "authorization_endpoint"},
accessToken => {xrds, "token_endpoint"},
userInfo => {xrds, "userinfo_endpoint"}
},
scope => "openid email profile",
accessTokenAcquireMethod => post,
clientSecretPassMethod => urlencoded,
accessTokenPassMethod => urlencoded,
customData => #{}
},
authorityDelegation => #{
enabled => true,
tokenPrefix => "google:"
},
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => undefined,
custom => undefined
},
entitlementMapping => #{
enabled => false
}
}
}}
# Facebook config (OpenID Connect)
click to expand
{facebook, #{
displayName => "Facebook",
iconPath => "/assets/images/auth-providers/facebook.svg",
iconBackgroundColor => "#5B87C5",
protocol => openid,
protocolConfig => #{
plugin => default_oidc_plugin,
pluginConfig => #{
clientId => "****************************************************",
clientSecret => "****************************************************",
endpoints => #{
authorize => "https://www.facebook.com/dialog/oauth",
accessToken => "https://graph.facebook.com/oauth/access_token",
userInfo => "https://graph.facebook.com/me"
},
scope => "email",
accessTokenAcquireMethod => get,
clientSecretPassMethod => urlencoded,
accessTokenPassMethod => urlencoded,
customData => #{
userInfo => #{
parameters => #{
"fields" => "email,name"
}
}
}
},
authorityDelegation => #{
enabled => true,
tokenPrefix => "facebook:"
},
attributeMapping => #{
subjectId => {required, "id"},
fullName => {required, {any, ["name", "fullName"]}},
username => {optional, "username"},
emails => {optional, "email"},
entitlements => undefined,
custom => undefined
},
entitlementMapping => #{
enabled => false
}
}
}}
# EGI config (OpenID Connect)
click to expand
{egi, #{
displayName => "EGI",
iconPath => "/assets/images/auth-providers/egi.svg",
iconBackgroundColor => "#FFFFFF",
protocol => openid,
protocolConfig => #{
plugin => default_oidc_plugin,
pluginConfig => #{
clientId => "****************************************************",
clientSecret => "****************************************************",
endpoints => #{
xrds => "https://aai-dev.egi.eu/auth/realms/egi/.well-known/openid-configuration"
},
scope => "openid email profile eduperson_entitlement",
clientSecretPassMethod => inAuthHeader,
accessTokenPassMethod => inAuthHeader
},
attributeMapping => #{
subjectId => {required, "sub"},
fullName => {required, {any, ["name", {concat, ["given_name", {str, " "}, "family_name"]}]}},
username => {optional, "preferred_username"},
emails => {optional, "email"},
entitlements => {optional, {filter, ".*#.*", "eduperson_entitlement"}},
custom => undefined
},
authorityDelegation => #{
tokenPrefix => "egi:"
},
entitlementMapping => #{
enabled => true,
adminGroup => "urn:mace:egi.eu:group:registry:egi-datahub-admins#aai.egi.eu",
parser => custom_entitlement_parser,
parserConfig => #{
originGroupType => organization,
topGroupType => team,
subGroupsType => team
}
}
}
}}
# PLGrid config (OpenID 2.0)
click to expand
{plgrid, #{
displayName => "PLGrid OpenID",
iconPath => "/assets/images/auth-providers/plgrid.svg",
iconBackgroundColor => "#026381",
protocol => openid,
protocolConfig => #{
plugin => plgrid_oidc_plugin,
pluginConfig => #{
xrds_endpoint => "https://openid.plgrid.pl/gateway"
},
authorityDelegation => #{
enabled => false
},
attributeMapping => #{
subjectId => {required, "openid.sreg.nickname"},
fullName => {required, "openid.sreg.fullname"},
username => {optional, "openid.sreg.nickname"},
emails => {optional, "openid.sreg.email"},
entitlements => {optional, "openid.ext1.value.teams"},
custom => undefined
},
entitlementMapping => #{
enabled => true,
parser => flat_entitlement_parser,
parserConfig => #{
groupType => team,
groupPrivilegesInVo => member,
userPrivileges => member
}
}
}
}}
# CERN config (SAML)
click to expand
{cern, #{
displayName => <<"CERN (eduGAIN)">>,
iconBackgroundColor => <<"#0053A1">>,
iconPath => <<"/assets/images/auth-providers/cern.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://met.refeds.org/met/entity/https%3A//cern.ch/login/?viewxml=true&federation=incommon-federation",
preferredSsoBinding => http_post,
attributeMapping => #{
subjectId => {required, "eduPersonUniqueID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonAffiliation"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "cern",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# CNRS config (SAML)
click to expand
{cnrs, #{
displayName => <<"CNRS (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/cnrs.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://met.refeds.org/met/entity/https%3A//janus.cnrs.fr/idp/?viewxml=true&federation=federation-education-recherche",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "cnrs",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# DESY config (SAML)
click to expand
{desy, #{
displayName => <<"DESY (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/desy.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://idp1.desy.de/idp/shibboleth",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonPrincipalName"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "desy",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# Elixir config (SAML)
click to expand
{elixir, #{
displayName => <<"Elixir">>,
iconBackgroundColor => <<"#FF7A04">>,
iconPath => <<"/assets/images/auth-providers/elixir.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://login.elixir-czech.org/proxy/saml2/idp/metadata.php",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonUniqueID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => true,
adminGroup => "vo:elixir_test/tm:HNSciCloud/tm:tsi-admin",
voGroupName => "elixir",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# EMBL config (SAML)
click to expand
{embl, #{
displayName => <<"EMBL (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/embl.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://idp.ebi.ac.uk/idp/shibboleth",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "embl",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# ESRF config (SAML)
click to expand
{esrf, #{
displayName => <<"ESRF (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/esrf.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://met.refeds.org/met/entity/https%3A//websso.esrf.fr/auth/realms/ESRF/?viewxml=true",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "esrf",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# IFAE config (SAML)
click to expand
{ifae, #{
displayName => <<"IFAE (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/ifae.jpg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://met.refeds.org/met/entity/https%3A//www.rediris.es/sir/ifaeidp/?viewxml=true",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "ifae",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# INFN config (SAML)
click to expand
{infn, #{
displayName => <<"INFN (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/infn.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://idp.infn.it/saml2/idp/metadata.php",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "infn",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# KIT config (SAML)
click to expand
{kit, #{
displayName => <<"KIT (eduGAIN)">>,
iconBackgroundColor => <<"#FFF">>,
iconPath => <<"/assets/images/auth-providers/kit.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://met.refeds.org/met/entity/https%3A//idp.scc.kit.edu/idp/shibboleth/?viewxml=true",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonPrincipalName"},
fullName => {optional, "surName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "kit",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# STFC config (SAML)
click to expand
{stfc, #{
displayName => <<"STFC (eduGAIN)">>,
iconBackgroundColor => <<"#1C3764">>,
iconPath => <<"/assets/images/auth-providers/stfc.svg">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "https://met.refeds.org/met/entity/https%3A//idp02.stfc.ac.uk/shibboleth/?viewxml=true",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, "displayName"},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "mail"},
entitlements => {optional, "eduPersonEntitlement"},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "stfc",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}
# UnitedID config (SAML)
click to expand
{unitedid, #{
displayName => <<"UnitedID">>,
iconBackgroundColor => <<"#ABDFF1">>,
iconPath => <<"/assets/images/auth-providers/unitedid.png">>,
protocol => saml,
protocolConfig => #{
metadataUrl => "http://md.unitedid.org/idp.xml",
preferredSsoBinding => http_redirect,
attributeMapping => #{
subjectId => {required, "eduPersonTargetedID"},
fullName => {optional, undefined},
username => {optional, "eduPersonPrincipalName"},
email => {optional, "eduPersonPrincipalName"},
entitlements => {optional, undefined},
custom => undefined
},
entitlementMapping => #{
enabled => false,
adminGroup => undefined,
voGroupName => "unitedid",
parser => flat_entitlement_parser,
parserConfig => #{
groupPrivilegesInVo => member,
groupType => team,
userPrivileges => member
}
}
}
}}