Upgrade process from 3.1.6 to 4.0 - GluuFederation/gluu-passport GitHub Wiki
This doc describes the steps to mutate a passport 3.1.6 into a 4.0 one:
Requisites
Upgrade oxtrust and oxauth. Stop passport.
Generate idp-initiated client
As per https://github.com/GluuFederation/community-edition-setup/tree/master/templates/passport.ldif#L1-L13 https://github.com/GluuFederation/community-edition-setup/blob/master/templates/passport_clients.ldif#L1-L15
Upgrade /etc/gluu/conf/passport-config.json
| Previous (3.1.x) property | Becomes in 4.x |
|---|---|
| passportConfigAPI | configurationEndpoint |
| applicationStartpoint | failureRedirectUrl |
The following remain the same: logLevel, clientId, keyPath, keyId, keyAlg.
As an example, this is how passport-config.json looks now:
{
"configurationEndpoint": "https://my.gluu.host/identity/restv1/passport/config",
"failureRedirectUrl": "https://my.gluu.host/oxauth/auth/passport/passportlogin.htm",
"logLevel": "debug",
"clientId": "@!D709.DD63.C2A5.9C6A!0001!2533.B35B!0008!B37C.2DF3",
"keyPath": "/etc/certs/passport-rp.pem",
"keyId": "890dc947-f5ab-476a-bba2-4ae8f297672d",
"keyAlg": "RS512"
}
Some properties in 3.1.x file were moved to LDAP. Later this is explained
Generate passport-central-config.json contents
The contents will end up imported under ou=oxpassport,ou=configuration,inum=...,ou=appliances,o=gluu (attribute gluuPassportConfiguration)
For reference, this is how a typical content looks like.
So based on the template, generate the 3 sections:
conf
For the logging section, use for level and consoleLogOnly the values already in passport-config.json (3.1.x)
For activeMQConf section, use the same values found under activeMQConf in passport-config.json (3.1.x), except for:
port: This is expected to be an integer (not a string as in 3.1.x). If conversion fails, simply set it to zeroisEnabledwhich is now simply calledenabledin 4.x
idpInitiated
For every key (section) found in in /etc/gluu/conf/passport-inbound-idp-initiated.json create an item inside authorizationParams filling values as follows:
| Property | Value |
|---|---|
| provider | The key value (e.g. "your_idp_name") |
| redirect_uri | redirect_uri value |
| response_type | response_type value |
| scope | take scope value (it's an array) and convert it into a space-separated string |
Account that if in passport-inbound-idp-initiated.json any of client_id or redirect_uri is empty in authorization_params, then no item in authorizationParams should be created.
For clientId use the client_id of the first occurrence of openidclient found passport-inbound-idp-initiated.json. However, if this value is empty, use the inum of the idp-initiated client generated at the beginning.
Examples:
-
If passport-inbound-idp-initiated.json is this (the default one), then the resulting
idpInitiatedsection should look like:{ "openidclient": { "authorizationEndpoint": "https://my.gluu.host/oxauth/restv1/authorize", "clientId": "ID of idp-initiated client", "acrValues": "passport_saml" }, "authorizationParams": [] } -
If passport-inbound-idp-initiated.json is
{ "your_idp_name_1": { "openidclient": { "server_uri": "something", "client_id": "client_id_1" }, "authorization_params": { "client_id": "client_id_1A", "redirect_uri": "redirect_uri_1", "acr_values": "acr1", "response_type": "code", "scope": ["openid", "user_name", "email"] } }, "your_idp_name_2": { "openidclient": { "server_uri": "something2", "client_id": "client_id_2" }, "authorization_params": { "client_id": "client_id_2A", "redirect_uri": "redirect_uri_2", "acr_values": "acr2", "response_type": "code token", "scope": ["openid"] } } }the result should be:
{ "openidclient": { "authorizationEndpoint": "https://my.gluu.host/oxauth/restv1/authorize", "clientId": "client_id_1", "acrValues": "passport_saml" }, "authorizationParams": [ { "provider" : "your_idp_name_1", "redirect_uri": "redirect_uri_1", "response_type": "code", "scope": "openid user_name email" }, { "provider" : "your_idp_name_2", "redirect_uri": "redirect_uri_2", "response_type": "code token", "scope": "openid" } ] }
providers
In 3.1.x the providers information is found at 2 places: LDAP and /etc/gluu/conf/passport-saml-config.json. LDAP has info about oauth-based providers, while the file has info about SAML providers.
oauth providers
For every LDAP attribute gluuPassportConfiguration under ou=oxpassport,ou=configuration,inum=...,ou=appliances,o=gluu create an item inside providers the following way:
| Property | Value |
|---|---|
| id | Use the value of strategy field |
| displayName | Use the value of strategy field |
| type | Use "oauth" if strategy is any of dropbox, facebook, github, google, linkedin, |
| mapping | Use the value of strategy field if strategy is any of dropbox, facebook, github, google, linkedin, openidconnect, tumblr, twitter, windowslive, yahoo. Otherwise use "openidconnect-default" |
| enabled | use true |
| logo_img | Lookup value2 where value1 is "logo_img" inside fieldset. If not found, do not set this property |
| requestForEmail | Lookup value2 where value1 is "requestForEmail" inside fieldset. If it equals the string "true", use true (as boolean). Otherwise, do not set this property |
| emailLinkingSafe | Lookup value2 where value1 is "emailLinkingSafe" inside fieldset. If it equals the string "true", use true (as boolean). Otherwise, do not set this property |
Fill property passportStrategyId according to the following rules:
| mapping value | Value for passportStrategyId |
|---|---|
| github | passport-github |
| openidconnect-default | passport-openidconnect |
| passport-twitter | |
| yahoo | passport-yahoo-oauth2 |
| tumblr | passport-tumblr |
| @sokratis/passport-linkedin-oauth2 | |
| passport-google-oauth2 | |
| passport-facebook | |
| dropbox | passport-dropbox-oauth2 |
| windowslive | passport-windowslive |
Fill a dictionary named "options" the following way: for every field (in fieldset) use value1 for the key and value2 for value. Ignore fields when value1 is any of logo_img, requestForEmail, emailLinkingSafe.
Example. Suppose the following is in LDAP:
gluuPassportConfiguration: {"strategy": "myOP", "fieldset": [{"value1": "logo_img", "value2": "some_url"}, {"value1": "requestForEmail", "value2": "true"}, {"value1": "extraPropertyA", "value2": "AHA"}, {"value1": "extraPropertyB", "value2": "WTF"}]}
gluuPassportConfiguration: {"strategy": "google", "fieldset": [{"value1": "logo_img", "value2" : "img/gugol.png"}, {"value1": "clientID", "value2": "some_client_id"}, {"value1": "clientSecret", "value2": "some_client_secret"}]}
gluuPassportConfiguration: {"strategy": "github", "fieldset": [{"value1": "someProperty", "value2" : "Nothing"}]}
This should generate:
[
{
"id": "myOP",
"displayName": "myOP",
"type": "openidconnect",
"mapping" : "openidconnect-default",
"enabled": true,
"logo_img" : "some_url",
"requestForEmail": true,
"passportStrategyId": "passport-openidconnect",
"options": {
"extraPropertyA": "AHA",
"extraPropertyB": "WTF"
}
},
{
"id": "google",
"displayName": "google",
"type": "oauth",
"mapping" : "google",
"enabled": true,
"logo_img" : "img/gugol.png",
"passportStrategyId": "passport-google-oauth2",
"options": {
"clientID": "some_client_id",
"clientSecret": "some_client_secret"
}
},
{
"id": "github",
"displayName": "github",
"type": "oauth",
"mapping" : "github",
"enabled": true,
"passportStrategyId": "passport-github",
"options": {
"someProperty": "Nothing"
}
}
]
SAML providers
Besides the oauth providers, we also have to add the SAML ones to the providers array.
So for every key in passport-saml-config.json we have to create an item this way:
| Property | Value |
|---|---|
| id | Use key |
| displayName | Use key |
| type | Use "saml" |
| enabled | Use propery enable from json file. Convert it to boolean beforehand |
| logo_img | As stored in logo_img property of json file |
| requestForEmail | As stored in requestForEmail property of json file. If absent, do not set this property |
| emailLinkingSafe | As stored in emailLinkingSafe property of json file. If absent, do not set this property |
| passportStrategyId | Use "passport-saml" |
| mapping | Use key |
Fill a dictionary named "options" with all the subkeys present in reverseMapping and their corresponding values except for enable, logo_img, requestForEmail and emailLinkingSafe. All dictionary values must be stored as strings regardless of how they appear in the original passport-saml-config.json file.
Create a .js file under a ~/temp/mappings directory with the name of the key. For instance, if the key is "My_Provider", a "My_Provider.js" can be created. Files created will be moved to its final destination afterwards
For generating files use this template:
module.exports = profile => {
return {
local_key_0: profile["remote_key_val_0"],
...
local_key_n: profile["remote_key_val_n"]
}
}
Where local_key_i is the item at position i in generic_local_attributes_list and remote_key_val_i is the value of a key in reverseMapping so that such key has the same name than the i-th element in generic_remote_attributes_list.
Remarks:
- Both
generic_remote_attributes_listandgeneric_local_attributes_listare the comma-separated lists found in the configuration properties of thepassport-samlscript. - Both lists have the same length.
- If for a value i, the i-th element of
generic_remote_attributes_listis "provider", ignore and continue with the next value of i. - If there is no match in the reverseMapping with respect to
generic_remote_attributes_list, ignore and continue with the next value of i.
The above is better explained using an example. Assume the following parameterization of passport_saml script in a customer's installation:
...
oxConfigurationProperty: {"value1":"generic_remote_attributes_list","value2":"username, email, name, name, givenName, familyName, provider}
oxConfigurationProperty: {"value1":"generic_local_attributes_list" ,"value2":"uid, mail, cn, displayName, givenName, sn, provider"}
...
And assume the reverseMapping in passport-saml-config has the following:
{
"email": "email",
"username": "urn:oid:0.9.2342.19200300.100.1.1",
"id": "urn:oid:0.9.2342.19200300.100.1.1",
"name": "urn:oid:2.5.4.42",
"givenName": "urn:oid:2.5.4.42",
"provider": "issuer"
}
local_key_0 is uid (the first element in the "local" list). To compute remote_key_val_0, we pick the 0-th element in "remote", that is,
username and then search for it in the reverseMapping. The following is found "username": "urn:oid:0.9.2342.19200300.100.1.1" so the value needed is "urn:oid:0.9.2342.19200300.100.1.1" yielding:
uid: profile["urn:oid:0.9.2342.19200300.100.1.1"]
Following the same idea, for local_key_1 (mail), "email" is searched in the reverse mapping, thus yielding:
mail: profile["email"],
Note that local_key_5 is not generated since familyName is not part of reverse mapping. local_key_6 is not generated since the 6th key in the remote list is "provider".
Example with SAML providers
Here it goes an example that sums up all of the previous section. Assume passport-saml-config.json has:
{
"your_idp_name1": {
"entryPoint": "https://idp1.example.com/idp/profile/SAML2/POST/SSO",
"issuer": "urn:test:example",
"identifierFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
"enable": "true",
"cert": "your_idp_public_certicate_in_single_line",
"reverseMapping": {
"username": "urn:oid:0.9.2342.19200300.100.1.1",
"name": "urn:oid:2.16.840.1.113730.3.1.241"
}
},
"your_idp_name2": {
"entryPoint": "entrypoint2",
"issuer": "urn:test",
"identifierFormat": "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
"enable":"false",
"cert":"the cert",
"acceptedClockSkewMs": 20000,
"reverseMapping": {
"email" : "email",
"username": "urn:oid:0.9.2342.19200300.100.1.1",
"members": "urn:1.3.6.1.4.1.48710.1.3.121",
"provider" :"issuer"
}
}
}
and passport_saml script with:
...
oxConfigurationProperty: {"value1":"generic_remote_attributes_list","value2":"username, email, name, provider, members"}
oxConfigurationProperty: {"value1":"generic_local_attributes_list", "value2":"uid, mail, displayName, provider, memberOf"}
...
The providers generated will look like:
...
{
"id": "your_idp_name1",
"displayName": "your_idp_name1",
"type": "saml",
"enabled": true,
"passportStrategyId": "passport-saml",
"mapping": "your_idp_name1",
"options": {
"entryPoint": "https://idp1.example.com/idp/profile/SAML2/POST/SSO",
"issuer": "urn:test:example",
"identifierFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
"cert": "your_idp_public_certicate_in_single_line"
}
},
{
"id": "your_idp_name2",
"displayName": "your_idp_name2",
"type": "saml",
"enabled": false,
"passportStrategyId": "passport-saml",
"mapping": "your_idp_name2",
"options": {
"entryPoint": "entrypoint2",
"issuer": "urn:test",
"identifierFormat": "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
"cert": "the cert",
"acceptedClockSkewMs": "20000"
}
}
And the following files must have been created in ~/temp/mappings:
your_idp_name1.json:
module.exports = profile => {
return {
uid: profile["urn:oid:0.9.2342.19200300.100.1.1"],
displayName: profile["urn:oid:2.16.840.1.113730.3.1.241"]
}
}
your_idp_name2.json:
module.exports = profile => {
return {
uid: profile["urn:oid:0.9.2342.19200300.100.1.1"],
mail: profile["email"],
memberOf: profile["urn:1.3.6.1.4.1.48710.1.3.121"]
}
}
Backup and apply changes
-
Add a
.baksuffix to files passport-saml-config.json, passport-inbound-idp-initiated.json. Example: passport-saml-config.json.bak -
For
passport_socialandpassport_samlscripts, remove the propertiesgeneric_remote_attributes_listandgeneric_local_attributes_list. I think we should back up this somewhere beforehand -
Backup the current 3.1.6 node app /opt/gluu/node/passport and replace with latest app from https://ox.gluu.org/npm/passport/ (using as usual both the tgz and tar.gz files)
-
Backup the contents of existing
gluuPassportConfigurationattribute(s). Then remove them and insert only one with the stuff generated in the previous section (that condenses the 3 sections: conf, idpInitiated, and providers). -
Update both passport scripts with the latest ones (oxScript attr) and increase oxRevision attribute by one. Use this and this
-
Install the app (npm install ...)
-
Copy the files in
~/temp/mappingsinto/opt/gluu/node/passport/server/mappings(account the destination directory already exists and has several files). Then delete~/temp/mappings -
Start passport