Skip to content

Upgrade process from 3.1.6 to 4.0

Jose edited this page Oct 8, 2019 · 13 revisions

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 zero
  • isEnabled which is now simply called enabled in 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:

  1. If passport-inbound-idp-initiated.json is this (the default one), then the resulting idpInitiated section should look like:

    {
        "openidclient": {
            "authorizationEndpoint": "https://my.gluu.host/oxauth/restv1/authorize",
            "clientId": "ID of idp-initiated client",
            "acrValues": "passport_saml"
        },
        "authorizationParams": []
    }
    
  2. 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, openidconnect, tumblr, twitter, windowslive, yahoo. Otherwise use "openidconnect"
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
twitter passport-twitter
yahoo passport-yahoo-oauth2
tumblr passport-tumblr
linkedin @sokratis/passport-linkedin-oauth2
google passport-google-oauth2
facebook 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_list and generic_local_attributes_list are the comma-separated lists found in the configuration properties of the passport-saml script.
  • Both lists have the same length.
  • If for a value i, the i-th element of generic_remote_attributes_list is "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 .bak suffix to files passport-saml-config.json, passport-inbound-idp-initiated.json. Example: passport-saml-config.json.bak

  • For passport_social and passport_saml scripts, remove the properties generic_remote_attributes_list and generic_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 gluuPassportConfiguration attribute(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/mappings into /opt/gluu/node/passport/server/mappings (account the destination directory already exists and has several files). Then delete ~/temp/mappings

  • Start passport