Skip to content

Commit

Permalink
Adding support for ForceAuthn & IsPassive attributes in SAML Authn re…
Browse files Browse the repository at this point in the history
…quest
  • Loading branch information
harshgoyal committed Jun 29, 2022
1 parent 66e3b7a commit a23bd67
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
6 changes: 6 additions & 0 deletions build_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ func (sp *SAMLServiceProvider) buildAuthnRequest(includeSig bool) (*etree.Docume
authnRequest.CreateAttr("AssertionConsumerServiceURL", sp.AssertionConsumerServiceURL)
authnRequest.CreateAttr("IssueInstant", sp.Clock.Now().UTC().Format(issueInstantFormat))
authnRequest.CreateAttr("Destination", sp.IdentityProviderSSOURL)
if sp.ForceAuthn {
authnRequest.CreateAttr("ForceAuthn", "true")
}
if sp.IsPassive {
authnRequest.CreateAttr("IsPassive", "true")
}

// NOTE(russell_h): In earlier versions we mistakenly sent the IdentityProviderIssuer
// in the AuthnRequest. For backwards compatibility we will fall back to that
Expand Down
84 changes: 84 additions & 0 deletions build_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,87 @@ func TestRequestedAuthnContextIncluded(t *testing.T) {
require.Equal(t, el.Tag, "AuthnContextClassRef")
require.Equal(t, el.Text(), AuthnContextPasswordProtectedTransport)
}

func TestForceAuthnOmitted(t *testing.T) {
spURL := "https://sp.test"
sp := SAMLServiceProvider{
AssertionConsumerServiceURL: spURL,
AudienceURI: spURL,
IdentityProviderIssuer: spURL,
IdentityProviderSSOURL: "https://idp.test/saml/sso",
}

request, err := sp.BuildAuthRequest()
require.NoError(t, err)

doc := etree.NewDocument()
err = doc.ReadFromString(request)
require.NoError(t, err)

attr := doc.Root().SelectAttr("ForceAuthn")
require.Nil(t, attr)
}

func TestForceAuthnIncluded(t *testing.T) {
spURL := "https://sp.test"
sp := SAMLServiceProvider{
AssertionConsumerServiceURL: spURL,
AudienceURI: spURL,
IdentityProviderIssuer: spURL,
IdentityProviderSSOURL: "https://idp.test/saml/sso",
ForceAuthn: true,
}

request, err := sp.BuildAuthRequest()
require.NoError(t, err)

doc := etree.NewDocument()
err = doc.ReadFromString(request)
require.NoError(t, err)

attr := doc.Root().SelectAttr("ForceAuthn")
require.NotNil(t, attr)
require.Equal(t, "true", attr.Value)
}

func TestIsPassiveOmitted(t *testing.T) {
spURL := "https://sp.test"
sp := SAMLServiceProvider{
AssertionConsumerServiceURL: spURL,
AudienceURI: spURL,
IdentityProviderIssuer: spURL,
IdentityProviderSSOURL: "https://idp.test/saml/sso",
}

request, err := sp.BuildAuthRequest()
require.NoError(t, err)

doc := etree.NewDocument()
err = doc.ReadFromString(request)
require.NoError(t, err)

attr := doc.Root().SelectAttr("IsPassive")
require.Nil(t, attr)
}

func TestIsPassiveIncluded(t *testing.T) {
spURL := "https://sp.test"
sp := SAMLServiceProvider{
AssertionConsumerServiceURL: spURL,
AudienceURI: spURL,
IdentityProviderIssuer: spURL,
IdentityProviderSSOURL: "https://idp.test/saml/sso",
IsPassive: true,
}

request, err := sp.BuildAuthRequest()
require.NoError(t, err)

doc := etree.NewDocument()
err = doc.ReadFromString(request)
require.NoError(t, err)

attr := doc.Root().SelectAttr("IsPassive")
require.NotNil(t, attr)
require.Equal(t, "true", attr.Value)
}
9 changes: 9 additions & 0 deletions saml.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ type SAMLServiceProvider struct {
SignAuthnRequestsAlgorithm string
SignAuthnRequestsCanonicalizer dsig.Canonicalizer

// ForceAuthn attribute in authentication request forces the identity provider to
// re-authenticate the presenter directly rather than rely on a previous security context.
// NOTE: If both ForceAuthn and IsPassive are "true", the identity provider MUST NOT freshly
// authenticate the presenter unless the constraints of IsPassive can be met.
ForceAuthn bool
// IsPassive attribute in authentication request requires that the identity provider and the
// user agent itself MUST NOT visibly take control of the user interface from the requester
// and interact with the presenter in a noticeable fashion.
IsPassive bool
// RequestedAuthnContext allows service providers to require that the identity
// provider use specific authentication mechanisms. Leaving this unset will
// permit the identity provider to choose the auth method. To maximize compatibility
Expand Down

0 comments on commit a23bd67

Please sign in to comment.