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: Okta

This example shows how to configure Okta SAML2 authentication for use with PowerShell Universal.
Within Okta, you will need to configure your application similar to the following. HTTPS is required by SAML2, and you will need to include the URL for your PSU instance in the Single Sign On URL, followed by /Saml2/Acs. The path is case sensitive.
The Audience Restriction should be the URL of your PowerShell Universal server.
In order for your users to access PowerShell Universal, you will need to ensure they have been assigned to the Okta application.
Within the Sign On tab of your application, click the View SAML setup instructions button.
You will need to capture the two URLs and download the certificate for configuring PowerShell Universal. See the next step on how to use these URLs within the authentication.ps1 file.

authentication.ps1

The authentication.ps1 file is used for configuring PowerShell Universal.
Set-PSUAuthenticationMethod -Type "Saml2" `
-EntityId "https://localhost:5001" `
-IdentityProviderEntityId "http://www.okta.com/exk5dvbyzgASPiOFp5d7" `
-CallbackPath "https://localhost:5001" `
-SigningKey "C:\Users\adamr\Downloads\okta.cert" `
-SingleSignOnServiceUrl "https://dev-36706648.okta.com/app/dev-36706648_psusaml_1/exk5dvbyzgASPiOFp5d7/sso/saml"
Parameter
Description
Type
EntityId
This value should match what you put in Audience Restriction within Okta.
string
IdentityProviderEntityId
This is the value that was presented in the View SAML setup instructions page.
string
CallbackPath
This is the path that the user will be redirected to if no redirect path was provided
string
SigningKey
This is the certificate file that was downloaded on the View SAML setup instructions page.
string
SingleSignOnServiceUrl
This is the sign on URL that was provided on the View SAML setup instructions page.
string

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>
Copy link
On this page
Identity Provider Settings
Entity ID Settings
Additional Settings
ServiceCertificatePassword
Configure
Example: Okta
authentication.ps1
Example: Shibboleth
ldap.properties
relying-party.xml
attribute-resolver.xml
attribute-filter.xml