Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Note

This feature is available in V3.4 and later of the software.

Current File(s): conf/intercept/impersonate-intercept-config.xml, views/intercept/impersonate.vm, conf/access-control.xml

...

The "general" policy runs first up front and determines whether to actually offer the impersonation option. This is logically equivalent to attaching an activation condition to the flow itself, but the AccessControl service is reloadable, so using a policy is more flexible.

The "specific" policy runs after an account name is selected to decide whether to allow it.

...

Aside from the UI, all of the flow's configuration is actually just defining policies, either in conf/access-control.xml or an included file. In practice, a "real world" implementation of such policies would likely rely on some kind of directory or database of rules controlling which users can impersonate which users to which services, perhaps through group memberships resolved during initial attribute resolution.

For simple illustrative purposes, consider a rule that the flow is authorized only to users possessing a particular entitlement value, and then are allowed to impersonate any users named by a second custom attribute to services named by a third. This fully devolves the decision making to data that could be supplied from any directory or database, instead of internal rules hardcoded into the configuration.

The "specificgeneral" policy could be implemented by a script, but the example demonstrates a new Java class added to V3.4 that checks the values of a resolved IdPAttribute against a dynamically computed candidate value (or values) produced by functions, which can themselves be scripts or expressionsis a simple test of an entitlement attribute for a specific value that is intended to mean "allow this logged-in user to at least attempt impersonation", and uses the SimpleAttributePredicate Java class. This class is often used to implement authorization rules in the context-check interceptor.

The "specific" policy could be implemented by a somewhat-involved script, but the example below relies on a new Java class added to V3.4 that checks the values of a resolved IdPAttribute against a dynamically computed candidate value (or values) produced by functions, which can themselves be scripts or expressions. This DynamicAttributePredicate class relies on an injected map of attribute names to functions, instead of attribute names to strings. The mapped function objects return the data values that have to be found in the named attribute at runtime to be a valid match. It's indirect instead static/direct.

The example uses this trick to derive the values to look for from the actual impersonation attempt. The ID of the service and the ID of the impersonated user come from functions and those functions are what the example is putting in the map that the Java class calls.

Instead of a rule saying "can impersonate jdoe to service xyz", which would be static and hard to manage, the rule is saying "allow the impersonation of jdoe to xyz if jdoe is one of the values of the impersonatableUsernames IdPAttribute and xyz is one of the values of the impersonatableServices IdPAttribute".

Once you understand the idea, it's not a lot of configuration to maintain and supports a plausible real-world approach to authorizing the impersonation feature.

Code Block
languagexml
titleconf/access-control.xml
collapsetrue
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
                           
       default-init-method="initialize"
       default-destroy-method="destroy">

    <util:map id="shibboleth.AccessControlPolicies">
    
		<!-- Limits who can impersonate based on entitlement. -->
        <entry key="GeneralImpersonationPolicy">
            <bean parent="shibboleth.PredicateAccessControl">
                <constructor-arg>
                    <bean class="net.shibboleth.idp.profile.logic.SimpleAttributePredicate">
                        <property name="attributeValueMap">
                            <map>
                                <entry key="eduPersonEntitlement">
                                    <list>
                                        <value>https://example.org/entitlement/impersonation</value>
                                    </list>
                                </entry>
                            </map>
                        </property>
                    </bean>
                </constructor-arg>
            </bean>
        </entry>

		<!-- Controls the impersonation scenarios to allow. -->
        <entry key="SpecificImpersonationPolicy">
            <bean parent="shibboleth.PredicateAccessControl">
                <constructor-arg>
                    <bean parent="shibboleth.Conditions.AND">
                        <constructor-arg>
                            <bean class="net.shibboleth.idp.profile.logic.DynamicAttributePredicate">
                                <property name="attributeFunctionMap">
                                    <map>
                                        <entry key="impersonatableUsernames">
                                            <list>
                                                <bean parent="shibboleth.ContextFunctions.Expression"
                                                    c:expression="#input.getSubcontext(T(org.opensaml.profile.context.AccessControlContext)).getResource()" />
                                            </list>
                                        </entry>
                                    </map>
                                </property>
                            </bean>
                        </constructor-arg>
                        <constructor-arg>
                            <bean class="net.shibboleth.idp.profile.logic.DynamicAttributePredicate">
                                <property name="attributeFunctionMap">
                                    <map>
                                        <entry key="impersonatableServices">
                                            <list>
                                                <bean parent="shibboleth.RelyingPartyIdLookup.Simple" />
                                            </list>
                                        </entry>
                                    </map>
                                </property>
                            </bean>
                        </constructor-arg>
                    </bean>
                </constructor-arg>
            </bean>
        </entry>

    </util:map>

</beans>

...