Links

SAML2

SAML2 authentication for PowerShell Universal.
PowerShell Universal can be configured to integrate with a SAML2 identity provider. This documentation provides the details for configuring PSU with such a system.

Identity Provider Settings

You will need to configure your identity provider for the PowerShell Universal application. You will need to setup an acceptable entity ID and map attributes. PowerShell Universal requires that the name attribute is mapped. The attribute name needs to be the following.
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
You should map this to the user identity you wish to be used within PowerShell Universal.
Additional attributes can be mapped and will be available during role evaluation. You will find an example of configuring Shibboleth below.

Entity ID Settings

HTTPS is required for SAML2 authentication.
There are several basic settings you can configure in the PowerShell Universal admin console. To add SAML2 support, click Security \ Authentication. In the top right corner, you can select SAML2 from the drop down.
Once the SAML2 integration has been added, you can configure the basic settings for communicating with your identity provider. You will need at least the Entity ID and Identity Provider Entity ID configured.
Typically, these entity IDs are URLs configured within your identity provider.
Entity ID Settings
The service certificate is used for signing requests. It is not required. This can either be a path local to the PSU service or the distinguished name of a certificate installed in the Personal Computer Certificate store.

Additional Settings

In addition to the settings available within the admin console, you can also set the following within the authentication.ps1 config file.

ServiceCertificatePassword

If you are using a file path for your certificate and it requires a password, you can specify it via the -ServiceCertificatePassword of Set-PSUAuthenticationMethod. The value of this parameter is a SecureString. You can take advantage of the SecretManagement module to load secrets.
Set-PSUAuthenticationMethod `
-Type "Saml2" `
-EntityId "http://psu.ironman.local/sp" `
-IdentityProviderEntityId 'https://ironman.local/idp' `
-MetadataAddress 'https://idp.ironman.local/idp/shibboleth' `
-CallbackPath "https://localhost:5000/" `
-ServiceCertificate cert.pfx `
-ServiceCertificatePassword (Get-Secret -Name 'certPassword')

Configure

The -Configure parameter is a script block that can be used to set additional settings not exposed by the Set-PSUAuthenticationMethod. The script block will be called when the provider is configured and will receive a single parameter that contains an object with the options for the SAML2 authentication.
The object is of the type Saml2Options. The sub object of SPOptions can be found here.
Set-PSUAuthenticationMethod `
-Type "Saml2" `
-EntityId "http://psu.ironman.local/sp" `
-IdentityProviderEntityId 'https://ironman.local/idp' `
-MetadataAddress 'https://idp.ironman.local/idp/shibboleth' `
-Configure {
$options = $args[0]
$options.SPOptions.DiscoveryServiceUrl = 'https://idp.ironman.local/discovery'
}

Example: Shibboleth

This example shows how to configure Shibboleth for use with PowerShell Universal. It provides the very basic configuration and does not necessarily follow best practices.
This assumes that you have installed Shibboleth Identity Provider v4 with Active Directory integration.

ldap.properties

LDAP properties have been configured to authentication against the local domain using a Domain Administrator account. The LDAP URL has been configured and TLS has been disabled.
Below you will find the full example of the ldap.properties file.
# LDAP authentication (and possibly attribute resolver) configuration
# Note, this doesn't apply to the use of JAAS authentication via LDAP
## Authenticator strategy, either anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, adAuthenticator
idp.authn.LDAP.authenticator=adAuthenticator
## Connection properties ##
idp.authn.LDAP.ldapURL=ldap://ironman.local:389
idp.authn.LDAP.useStartTLS = false
# Time in milliseconds that connects will block
#idp.authn.LDAP.connectTimeout = PT3S
# Time in milliseconds to wait for responses
#idp.authn.LDAP.responseTimeout = PT3S
# Connection strategy to use when multiple URLs are supplied, either ACTIVE_PASSIVE, ROUND_ROBIN, RANDOM
#idp.authn.LDAP.connectionStrategy = ACTIVE_PASSIVE
## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust
idp.authn.LDAP.sslConfig = jvmTrust
## If using certificateTrust above, set to the trusted certificate's path
idp.authn.LDAP.trustCertificates=%{idp.home}/credentials/ldap-server.crt
## If using keyStoreTrust above, set to the truststore path
idp.authn.LDAP.trustStore=%{idp.home}/credentials/ldap-server.truststore
## Return attributes during authentication
idp.authn.LDAP.returnAttributes=passwordExpirationTime,loginGraceRemaining,sn,mail
## DN resolution properties ##
# Search DN resolution, used by anonSearchAuthenticator, bindSearchAuthenticator
# for AD: CN=Users,DC=example,DC=org
idp.authn.LDAP.baseDN=CN=Users,DC=ironman, DC=local
idp.authn.LDAP.subtreeSearch = true
idp.authn.LDAP.userFilter=(sAMAccountName={user})
# bind search configuration
# Format DN resolution, used by directAuthenticator, adAuthenticator
# for AD use idp.authn.LDAP.dnFormat=%[email protected]
idp.authn.LDAP.dnFormat=%[email protected]
# pool passivator, either none, bind or anonymousBind
#idp.authn.LDAP.bindPoolPassivator = none
# LDAP attribute configuration, see attribute-resolver.xml
# Note, this likely won't apply to the use of legacy V2 resolver configurations
idp.attribute.resolver.LDAP.ldapURL=%{idp.authn.LDAP.ldapURL}
idp.attribute.resolver.LDAP.connectTimeout=%{idp.authn.LDAP.connectTimeout:PT3S}
idp.attribute.resolver.LDAP.responseTimeout=%{idp.authn.LDAP.responseTimeout:PT3S}
idp.attribute.resolver.LDAP.connectionStrategy=%{idp.authn.LDAP.connectionStrategy:ACTIVE_PASSIVE}
idp.attribute.resolver.LDAP.baseDN=%{idp.authn.LDAP.baseDN:undefined}
idp.attribute.resolver.LDAP.bindDN=%{idp.authn.LDAP.bindDN:undefined}
idp.attribute.resolver.LDAP.useStartTLS=%{idp.authn.LDAP.useStartTLS:true}
idp.attribute.resolver.LDAP.trustCertificates=%{idp.authn.LDAP.trustCertificates:undefined}
idp.attribute.resolver.LDAP.searchFilter=(sAMAccountName=$resolutionContext.principal)
# LDAP pool configuration, used for both authn and DN resolution
#idp.pool.LDAP.minSize = 3
#idp.pool.LDAP.maxSize = 10
#idp.pool.LDAP.validateOnCheckout = false
#idp.pool.LDAP.validatePeriodically = true
#idp.pool.LDAP.validatePeriod = PT5M
#idp.pool.LDAP.validateDN =
#idp.pool.LDAP.validateFilter = (objectClass=*)
#idp.pool.LDAP.prunePeriod = PT5M
#idp.pool.LDAP.idleTime = PT10M
#idp.pool.LDAP.blockWaitTime = PT3S

relying-party.xml

The relying-party.xml file has been updated to enable open IdP. This means that any entity ID can communicate with the identity provider. You can also configure this to enforce specific entity IDs. The default configure has also been adjusted to use the SAML2.AttributeQuery bean.
<?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">
<!--
Unverified RP configuration, defaults to no support for any profiles. Add <ref> elements to the list
to enable specific default profile settings (as below), or create new beans inline to override defaults.
"Unverified" typically means the IdP has no metadata, or equivalent way of assuring the identity and
legitimacy of a requesting system. To run an "open" IdP, you can enable profiles here.
-->
<bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
<property name="profileConfigurations">
<list>
<bean parent="SAML2.SSO" p:encryptAssertions="false" />
</list>
</property>
</bean>
<!-- Default configuration, with default settings applied for all profiles. -->
<bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
<property name="profileConfigurations">
<list>
<!-- SAML 1.1 and SAML 2.0 AttributeQuery are disabled by default. -->
<!--
<bean parent="Shibboleth.SSO" />
<ref bean="SAML1.AttributeQuery" />
<ref bean="SAML1.ArtifactResolution" />
-->
<bean parent="SAML2.SSO" />
<ref bean="SAML2.ECP" />
<ref bean="SAML2.Logout" />
<ref bean="SAML2.AttributeQuery" />
<ref bean="SAML2.ArtifactResolution" />
<ref bean="Liberty.SSOS" />
</list>
</property>
</bean>
</beans>

attribute-resolver.xml

The attribute-resolver.xml file has been updated to use the LDAPDirectory Data Connector. It loads the email address, given name, SN, and display name from Active Directory. It then maps the Principal Name, which will be the username of the user logging in, to the required claim type using an attribute encoder.
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is an EXAMPLE configuration file containing some example attributes
based on some commonly used approaches when LDAP is the principal data source.
Not all attribute definitions or data connectors are demonstrated, but some
LDAP attributes common to Shibboleth deployments (and some not so common) are
included.
This example is in no way usable as a substitute for reading the documentation.
-->
<AttributeResolver
xmlns="urn:mace:shibboleth:2.0:resolver"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
<!-- ========================================== -->
<!-- Attribute Definitions -->
<!-- ========================================== -->
<!-- Simple attributes are exported directly from the LDAP connector. -->
<AttributeDefinition id="uid" xsi:type="PrincipalName" />
<AttributeDefinition id="username" xsi:type="PrincipalName">
<AttributeEncoder xsi:type="SAML2String" name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" friendlyName="displayName" encodeType="false" />
</AttributeDefinition>
<!-- ========================================== -->
<!-- Data Connectors -->
<!-- ========================================== -->
<!-- Example LDAP Connector -->
<DataConnector id="myLDAP" xsi:type="LDAPDirectory"
ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
baseDN="%{idp.attribute.resolver.LDAP.baseDN}"
principal="%{idp.attribute.resolver.LDAP.bindDN}"
principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS:true}"
connectTimeout="%{idp.attribute.resolver.LDAP.connectTimeout}"
responseTimeout="%{idp.attribute.resolver.LDAP.responseTimeout}"
connectionStrategy="%{idp.attribute.resolver.LDAP.connectionStrategy}"
noResultIsError="true"
multipleResultsIsError="true"
excludeResolutionPhases="c14n/attribute"
exportAttributes="mail displayName sn givenName">
<FilterTemplate>
<![CDATA[
%{idp.attribute.resolver.LDAP.searchFilter}
]]>
</FilterTemplate>
<ConnectionPool
minPoolSize="%{idp.pool.LDAP.minSize:3}"
maxPoolSize="%{idp.pool.LDAP.maxSize:10}"
blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
validateTimerPeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"
validateDN="%{idp.pool.LDAP.validateDN:}"
validateFilter="%{idp.pool.LDAP.validateFilter:(objectClass=*)}"
expirationTime="%{idp.pool.LDAP.idleTime:PT10M}"/>
</DataConnector>
</AttributeResolver>

attribute-filter.xml

The attribute-filter.xml file has been updated to release several of the attributes mapped by the LDAPDirectory data connector as well as the user name that will be used as the identity within PowerShell Universal.
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is an EXAMPLE policy file. While the policy presented in this
example file is illustrative of some simple cases, it relies on the names of
non-existent example services and the example attributes demonstrated in the
default attribute-resolver.xml file.
This example does contain some usable "general purpose" policies that may be
useful in conjunction with specific deployment choices, but those policies may
not be applicable to your specific needs or constraints.
-->
<AttributeFilterPolicyGroup id="ShibbolethFilterPolicy"
xmlns="urn:mace:shibboleth:2.0:afp"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:mace:shibboleth:2.0:afp http://shibboleth.net/schema/idp/shibboleth-afp.xsd">
<AttributeFilterPolicy id="example1">
<PolicyRequirementRule xsi:type="ANY" />
<AttributeRule attributeID="username">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
<AttributeRule attributeID="displayName">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
<AttributeRule attributeID="uid">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
<AttributeRule attributeID="mail">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
<AttributeRule attributeID="sn">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
</AttributeFilterPolicy>
</AttributeFilterPolicyGroup>