Skip to end of metadata
Go to start of metadata

Skip this section unless you know you need to support SAML logins to certain SPs based on IP-ranges alone, i.e., without usernames and passwords.

In order to interoperate with e-resource providers (publishers, etc.) that have standardised on using only SAML (or "Shibboleth", as it's often still called in library communities) for access to their licensed resources – including "library walk-in users" who may not have personal credentials for authentication – the Shibboleth Identity Provider (IDP) supports IP-address-based authentication. This way the Service Provider (SP) will receive a SAML assertion as usual, but the subject does not need to be provisioned with login credentials as long as she is accessing the IDP from within previously configured IP network ranges. The subject will still need to chose to "log in" at the SP and select the institution she wants to use for her login, same as in the off-campus use-case. The difference being that instead of prompting for a username and password the IDP will automatically and transparently log her in with a generic (surrogate) identity that's the same for all subjects accessing the IDP from within the specified IP ranges.

How it works

The Shibboleth IDP can "authenticate" a configurable "user" from a list of IP address ranges, without ever showing a login form asking for username and password.

  • All access from within the configured IP ranges will be mapped to that "user" and the IDP will resolve attributes for that user, and release them to services using the usual methods (same as for other authenticated subjects).
  • All access from outside of the configured IP ranges will invoke the usual form(s) of authentication, most often based on username and password.
  • Both methods are active and the appropriate one will be chosen by the IDP based on the IP address of the subject accessing the IDP.

Since the person accessing the service (and the IDP) is not known individually (other than being someone using a web browser on a device within a given IP address range) only non-personal, generic data can be asserted about the subject. Commonly only the common-lib-terms eduPersonEntitlement and/or an eduPersonScopedAffiliation of "library-walk-in" (scoped to the institution asserting it) will be sent to Service Providers.

All subjects mapped to a given "user" will apear as one

For the reason given above (subjects who don't authenticate with personal credentials at the IDP cannot reliably be identified by the IDP merely based on an IP address) the IDP cannot assert identities that differ (or rather: remain unchanged) per subject, as it has no way of knowing whether a given IP address still represents the same subject as moments before.

Additionally, the IDP will set the so-called Authentication Context Class Reference to "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol" whenever IP-based authentication has been used, so the Service Provider has a way to check for the authentication method that was being used in order to detect IP-based vs. other authentication methods (e.g. urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport).

Enable IP-based authentication

Some of the required changes documented below will only become active after a restart of the IDP application, so restart the IDP after you're done.

Activate support for IP authentication

In order to activate the built-in support for IP-authentication in the Shibboleth v3 IDP you simply change the property idp.authn.flows in /opt/shibboleth-idp/conf/idp.properties from (only) Password to IPAddress|Password and define a property with the name of the technical account to use within the IDP configuration. That account does not (and should not) exist in any of your source systems, so just make sure its name will not collide with any existing or future account for a real person.

/opt/shibboleth-idp/conf/idp.properties
  # Regular expression matching login flows to enable, e.g. IPAddress|Password
- idp.authn.flows= Password
+ idp.authn.flows= IPAddress|Password
+ 
+ local.walk-in.principal= libraryWalkInUserAccount

Configure affected IP ranges

Uncomment and configure the appropriate IP ranges (and the desired user account to map them to, see below) in /opt/shibboleth-idp/conf/authn/ipaddress-authn-config.xml within the map with the id="shibboleth.authn.IPAddress.Mappings". See the Shibboleth documentation for an example, and the distributed configuration file already contains this example by default, to be adapted as needed.

  • This is were you'd reference all IP ranges that should trigger "IP-authentication" instead of the normal login method.
  • Within the <list> element add as many <value> elements as needed, with one <value> element for each IP range, in CIDR notation.
  • The "user" every access from within these network ranges will be mapped to will be set according to the property (see above).
/opt/shibboleth-idp/conf/authn/ipaddress-authn-config.xml
<util:map id="shibboleth.authn.IPAddress.Mappings">
    <entry key="%{local.walk-in.principal}">
        <list>
            <value>192.160.0.0/24</value>
            <value>10.0.0.0/8</value>
        </list>
    </entry>
</util:map>

Resolve the right attributes

Each time someone from within the configured network ranges accesses the IDP the authenticated subject within the IDP will be the username set in the property above. An account for that username doesn't need to exist in any of your source systems (e.g. in an LDAP directory) but we still need to resolve the desired attributes for it. This can all be done within the IDP's attribute resolver, by default in /opt/shibboleth-idp/conf/attribute-resolver.xml, see our documentation. In fact all examples below are ment to amend a configuration that closely follows our documentation already.

First, make the authenticated subject from the IP address mappings available as internal attribute. (Only needed if you do not already have an attribute definition of type "PrincipalName" in your resolver. If you do simply reference your PrincipalName-type attribute definition below instead.)

Add PrincipalName attribute definition (if you have none)
<AttributeDefinition id="Principal" xsi:type="PrincipalName" dependencyOnly="true"/>

Then resolve a library-walk-in affiliation for the surrogate user:

Add library-walk-in affiliation if user is library-walk-in surrogate
<AttributeDefinition id="libraryWalkIn_Affiliation" xsi:type="Mapped" dependencyOnly="true">
    <InputAttributeDefinition ref="Principal" />
    <ValueMap>   
        <ReturnValue>library-walk-in</ReturnValue>
        <SourceValue>^%{local.walk-in.principal}$</SourceValue>
    </ValueMap>
</AttributeDefinition>

Finally, amend your existing eduPersonAffiliation definition with a dependency on the newly created libraryWalkIn_Affiliation, effectively adding the library-walk-in affiliation (only) to the library-walk-in user:

Pull in library-walk-in affiliation
  <AttributeDefinition id="eduPersonAffiliation" xsi:type="Mapped" dependencyOnly="true">
+   <InputAttributeDefinition ref="libraryWalkIn_Affiliation" />
    <InputDataConnector ref="myLDAP" attributeNames="..." />

As for the common-lib-terms eduPersonEntitlement value: If your attribute definition for the eduPersonEntitlement is up-to-date with this documentation it should already contain a mapping from the library-walk-in affiliation to the common-lib-terms entitlement value. Otherwise just bring your local eduPersonEntitlement attribute definition in line with our documentation. (wink)

Release the affiliation attribute

Follow the examples from our Library Services documentation, specifically the attribute filter policy with an id="LibrarySPsScopedAffiliation" takes care of releasing the eduPersonScopedAffiliation attribute with the "library-walk-in" value created above.

Prevent any further attribute lookup and release

In order to make sure no other data is being resolved for the surrogate user (and later possibly also released to services) add the folowing bean to /opt/shibboleth-idp/conf/global.xml (anywhere within the enclosing beans XML element) so that it can later be referenced from the attribute resolver and NameID configuration. (This will evaluate to true whenever the IDP is dealing with a real authenticated subject, not with the library-walk-in surrogate.)

/opt/shibboleth-idp/conf/global.xml
<bean id="NOT_libraryWalkIn" parent="shibboleth.Conditions.NOT">
    <constructor-arg>
        <bean parent="shibboleth.Conditions.SubjectName" c:collection="#{'%{local.walk-in.principal}'}" />
    </constructor-arg>
</bean>

Then reference this bean with an activationConditionRef XML attribute in every "real" DataConnector you have configured in your attribute resolver, in order to prevent those from being run for the library-walk-in user. E.g. for the LDAP data connector:

/opt/shibboleth-idp/conf/attribute-resolver.xml
- <DataConnector id="myLDAP" xsi:type="LDAPDirectory"
+ <DataConnector id="myLDAP" xsi:type="LDAPDirectory" activationConditionRef="NOT_libraryWalkIn"

Likewise add this activationConditionRef="NOT_libraryWalkIn" to other data connectors you may have defined, especially if those are "expensive" (e.g. lookups from a slow service) or indiscriminately produce attribute values for "everyone".

If you're also supporting persistent NameIDs in your IDP you will want to add this activation condition to the SAML2 persistent NameID generator as well. In practice that requires commenting out (or removing) the default ref XML element used to enable support for persistent NameIDs and replacing it with a slightly amended XML bean element that includes the activation condition, like this:

/opt/shibboleth-idp/conf/saml-nameid.xml
  <!-- Uncommenting this bean requires configuration in saml-nameid.properties. -->
- <ref bean="shibboleth.SAML2PersistentGenerator" />
+ <bean parent="shibboleth.SAML2PersistentGenerator" p:activationCondition-ref="NOT_libraryWalkIn" />
  • No labels