Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Support getting Status code back from SAML Provider Response #31

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion authnrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func NewAuthnRequest() *AuthnRequest {
Url: "", // caller must populate ar.AppSettings.Issuer
SAML: "urn:oasis:names:tc:SAML:2.0:assertion",
},
IssueInstant: time.Now().UTC().Format(time.RFC3339Nano),
IssueInstant: time.Now().UTC().Format(time.RFC3339),
NameIDPolicy: NameIDPolicy{
XMLName: xml.Name{
Local: "samlp:NameIDPolicy",
Expand Down
19 changes: 14 additions & 5 deletions authnresponse.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func NewSignedResponse() *Response {
SAMLSIG: "http://www.w3.org/2000/09/xmldsig#",
ID: util.ID(),
Version: "2.0",
IssueInstant: time.Now().UTC().Format(time.RFC3339Nano),
IssueInstant: time.Now().UTC().Format(time.RFC3339),
Issuer: Issuer{
XMLName: xml.Name{
Local: "saml:Issuer",
Expand Down Expand Up @@ -203,7 +203,7 @@ func NewSignedResponse() *Response {
SAML: "urn:oasis:names:tc:SAML:2.0:assertion",
Version: "2.0",
ID: util.ID(),
IssueInstant: time.Now().UTC().Format(time.RFC3339Nano),
IssueInstant: time.Now().UTC().Format(time.RFC3339),
Issuer: Issuer{
XMLName: xml.Name{
Local: "saml:Issuer",
Expand Down Expand Up @@ -232,7 +232,7 @@ func NewSignedResponse() *Response {
Local: "saml:SubjectConfirmationData",
},
InResponseTo: "",
NotOnOrAfter: time.Now().Add(time.Minute * 5).UTC().Format(time.RFC3339Nano),
NotOnOrAfter: time.Now().Add(time.Minute * 5).UTC().Format(time.RFC3339),
Recipient: "",
},
},
Expand All @@ -241,8 +241,8 @@ func NewSignedResponse() *Response {
XMLName: xml.Name{
Local: "saml:Conditions",
},
NotBefore: time.Now().Add(time.Minute * -5).UTC().Format(time.RFC3339Nano),
NotOnOrAfter: time.Now().Add(time.Minute * 5).UTC().Format(time.RFC3339Nano),
NotBefore: time.Now().Add(time.Minute * -5).UTC().Format(time.RFC3339),
NotOnOrAfter: time.Now().Add(time.Minute * 5).UTC().Format(time.RFC3339),
AudienceRestrictions: []AudienceRestriction{},
},
AttributeStatement: AttributeStatement{
Expand Down Expand Up @@ -348,6 +348,15 @@ func (r *Response) CompressedEncodedSignedString(privateKeyPath string) (string,
return b64XML, nil
}

// GetStatusCode will check for nested status code values
func (r *Response) GetStatusCode() string {
statusCode := r.Status.StatusCode
if statusCode.StatusCode != nil {
return statusCode.StatusCode.Value
}
return statusCode.Value
}

// GetAttribute by Name or by FriendlyName. Return blank string if not found
func (r *Response) GetAttribute(name string) string {
for _, attr := range r.Assertion.AttributeStatement.Attributes {
Expand Down
54 changes: 54 additions & 0 deletions authnresponse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package saml

import (
"encoding/xml"
"testing"

"github.com/stretchr/testify/assert"
)

func TestStatus_Success(t *testing.T) {
response := NewSignedResponse()
assert.NotNil(t, response)
status := response.GetStatusCode()
assert.Equal(t, "urn:oasis:names:tc:SAML:2.0:status:Success", status)
}

func TestStatus_EmptyStatusCode(t *testing.T) {
response := NewSignedResponse()
response.Status = Status{}
assert.NotNil(t, response)
status := response.GetStatusCode()
assert.Equal(t, "", status)
}

func TestStatus_Failure(t *testing.T) {
response := NewSignedResponse()
response.Status = Status{
XMLName: xml.Name{
Local: "samlp:Status",
},
StatusCode: StatusCode{
XMLName: xml.Name{
Local: "samlp:StatusCode",
},
Value: "urn:oasis:names:tc:SAML:2.0:status:Requester",
StatusCode: &StatusCode{
XMLName: xml.Name{
Local: "samlp:StatusCode",
},
Value: "urn:oasis:names:tc:SAML:2.0:status:RequestDenied",
},
},
StatusMessage: StatusMessage{
XMLName: xml.Name{
Local: "samlp:StatusMessage",
},
Value: "Invalid request, ACS Url in request https://example.com/callback doesn't match configured ACS Url https://test.com/callback.",
},
}
assert.NotNil(t, response)
status := response.GetStatusCode()
assert.Equal(t, "urn:oasis:names:tc:SAML:2.0:status:RequestDenied", status)
assert.Equal(t, "Invalid request, ACS Url in request https://example.com/callback doesn't match configured ACS Url https://test.com/callback.", response.Status.StatusMessage.Value)
}
14 changes: 10 additions & 4 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ type AuthnRequest struct {
AssertionConsumerServiceURL string `xml:"AssertionConsumerServiceURL,attr"`
Destination string `xml:"Destination,attr"`
IssueInstant string `xml:"IssueInstant,attr"`
AssertionConsumerServiceIndex int `xml:"AssertionConsumerServiceIndex,attr"`
AttributeConsumingServiceIndex int `xml:"AttributeConsumingServiceIndex,attr"`
Issuer Issuer `xml:"Issuer"`
NameIDPolicy NameIDPolicy `xml:"NameIDPolicy"`
Expand Down Expand Up @@ -240,8 +239,9 @@ type SubjectConfirmation struct {
}

type Status struct {
XMLName xml.Name
StatusCode StatusCode `xml:"StatusCode"`
XMLName xml.Name
StatusCode StatusCode `xml:"StatusCode"`
StatusMessage StatusMessage `xml:"StatusMessage"`
}

type SubjectConfirmationData struct {
Expand All @@ -259,8 +259,14 @@ type NameID struct {
}

type StatusCode struct {
XMLName xml.Name
StatusCode *StatusCode `xml:"StatusCode"`
Value string `xml:",attr"`
}

type StatusMessage struct {
XMLName xml.Name
Value string `xml:",attr"`
Value string `xml:",chardata"`
}

type AttributeValue struct {
Expand Down