github.com/crewjam/saml@v0.4.14/schema_test.go (about)

     1  package saml
     2  
     3  import (
     4  	"encoding/xml"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/beevik/etree"
     9  	"gotest.tools/assert"
    10  	is "gotest.tools/assert/cmp"
    11  )
    12  
    13  func TestAttributeXMLRoundTrip(t *testing.T) {
    14  	expected := Attribute{
    15  		FriendlyName: "TestFriendlyName",
    16  		Name:         "TestName",
    17  		NameFormat:   "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
    18  		Values: []AttributeValue{{
    19  			Type:  "xs:string",
    20  			Value: "test",
    21  		}},
    22  	}
    23  
    24  	doc := etree.NewDocument()
    25  	doc.SetRoot(expected.Element())
    26  	x, err := doc.WriteToBytes()
    27  	assert.Check(t, err)
    28  	assert.Check(t, is.Equal("<saml:Attribute FriendlyName=\"TestFriendlyName\" Name=\"TestName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xs:string\">test</saml:AttributeValue></saml:Attribute>",
    29  		string(x)))
    30  
    31  	var actual Attribute
    32  	err = xml.Unmarshal(x, &actual)
    33  	assert.Check(t, err)
    34  	assert.Check(t, is.DeepEqual(expected, actual))
    35  }
    36  
    37  func TestNameIDFormat(t *testing.T) {
    38  	var emptyString string
    39  	el := NameIDPolicy{
    40  		Format: &emptyString,
    41  	}
    42  	doc := etree.NewDocument()
    43  	doc.SetRoot(el.Element())
    44  	x, err := doc.WriteToBytes()
    45  	assert.Check(t, err)
    46  	assert.Check(t, is.Equal("<samlp:NameIDPolicy/>",
    47  		string(x)))
    48  }
    49  
    50  func TestAuthnStatementXMLRoundTrip(t *testing.T) {
    51  	authnInstant := time.Date(2020, 7, 21, 12, 30, 45, 0, time.UTC)
    52  	sessionNotOnOrAfter := time.Date(2020, 7, 22, 15, 0, 0, 0, time.UTC)
    53  	expected := AuthnStatement{
    54  		AuthnInstant:        authnInstant,
    55  		SessionIndex:        "index",
    56  		SessionNotOnOrAfter: &sessionNotOnOrAfter,
    57  	}
    58  
    59  	doc := etree.NewDocument()
    60  	doc.SetRoot(expected.Element())
    61  	x, err := doc.WriteToBytes()
    62  	assert.Check(t, err)
    63  	assert.Check(t, is.Equal(`<saml:AuthnStatement AuthnInstant="2020-07-21T12:30:45Z" SessionIndex="index" SessionNotOnOrAfter="2020-07-22T15:00:00Z"><saml:AuthnContext/></saml:AuthnStatement>`,
    64  		string(x)))
    65  
    66  	var actual AuthnStatement
    67  	err = xml.Unmarshal(x, &actual)
    68  	assert.Check(t, err)
    69  	assert.Check(t, is.DeepEqual(expected, actual))
    70  
    71  	x, err = xml.Marshal(expected)
    72  	assert.Check(t, err)
    73  	assert.Check(t, is.Equal(`<AuthnStatement AuthnInstant="2020-07-21T12:30:45Z" SessionIndex="index" SessionNotOnOrAfter="2020-07-22T15:00:00Z"><AuthnContext></AuthnContext></AuthnStatement>`,
    74  		string(x)))
    75  }
    76  
    77  func TestAuthnStatementMarshalWithoutSessionNotOnOrAfter(t *testing.T) {
    78  	authnInstant := time.Date(2020, 7, 21, 12, 30, 45, 0, time.UTC)
    79  	expected := AuthnStatement{
    80  		AuthnInstant:        authnInstant,
    81  		SessionIndex:        "index",
    82  		SessionNotOnOrAfter: nil,
    83  	}
    84  
    85  	doc := etree.NewDocument()
    86  	doc.SetRoot(expected.Element())
    87  	x, err := doc.WriteToBytes()
    88  	assert.Check(t, err)
    89  	assert.Check(t, is.Equal(`<saml:AuthnStatement AuthnInstant="2020-07-21T12:30:45Z" SessionIndex="index"><saml:AuthnContext/></saml:AuthnStatement>`,
    90  		string(x)))
    91  
    92  	var actual AuthnStatement
    93  	err = xml.Unmarshal(x, &actual)
    94  	assert.Check(t, err)
    95  	assert.Check(t, is.DeepEqual(expected, actual))
    96  }
    97  
    98  func TestRequestedAuthnContext(t *testing.T) {
    99  	expected := RequestedAuthnContext{
   100  		Comparison: "comparison",
   101  	}
   102  
   103  	doc := etree.NewDocument()
   104  	doc.SetRoot(expected.Element())
   105  	x, err := doc.WriteToBytes()
   106  	assert.Check(t, err)
   107  	assert.Check(t, is.Equal(`<samlp:RequestedAuthnContext Comparison="comparison"><saml:AuthnContextClassRef/></samlp:RequestedAuthnContext>`,
   108  		string(x)))
   109  }
   110  
   111  func TestArtifactResolveElement(t *testing.T) {
   112  	issueInstant := time.Date(2020, 7, 21, 12, 30, 45, 0, time.UTC)
   113  	expected := ArtifactResolve{
   114  		ID:           "index",
   115  		Version:      "version",
   116  		IssueInstant: issueInstant,
   117  		// Signature    *etree.Element
   118  	}
   119  
   120  	doc := etree.NewDocument()
   121  	doc.SetRoot(expected.Element())
   122  	x, err := doc.WriteToBytes()
   123  	assert.Check(t, err)
   124  	assert.Check(t, is.Equal(`<samlp:ArtifactResolve xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="index" Version="version" IssueInstant="2020-07-21T12:30:45Z"><samlp:Artifact/></samlp:ArtifactResolve>`,
   125  		string(x)))
   126  
   127  	var actual ArtifactResolve
   128  	err = xml.Unmarshal(x, &actual)
   129  	assert.Check(t, err)
   130  	assert.Check(t, is.DeepEqual(expected, actual))
   131  
   132  	x, err = xml.Marshal(expected)
   133  	assert.Check(t, err)
   134  	assert.Check(t, is.Equal(`<ArtifactResolve xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ID="index" Version="version" IssueInstant="2020-07-21T12:30:45Z"><Artifact xmlns="urn:oasis:names:tc:SAML:2.0:protocol"></Artifact></ArtifactResolve>`,
   135  		string(x)))
   136  }
   137  
   138  func TestArtifactResolveSoapRequest(t *testing.T) {
   139  	issueInstant := time.Date(2020, 7, 21, 12, 30, 45, 0, time.UTC)
   140  	expected := ArtifactResolve{
   141  		ID:           "index",
   142  		Version:      "version",
   143  		IssueInstant: issueInstant,
   144  		// Signature    *etree.Element
   145  	}
   146  
   147  	doc := etree.NewDocument()
   148  	doc.SetRoot(expected.SoapRequest())
   149  	x, err := doc.WriteToBytes()
   150  	assert.Check(t, err)
   151  	assert.Check(t, is.Equal(`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><samlp:ArtifactResolve xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="index" Version="version" IssueInstant="2020-07-21T12:30:45Z"><samlp:Artifact/></samlp:ArtifactResolve></soapenv:Body></soapenv:Envelope>`,
   152  		string(x)))
   153  }
   154  
   155  func TestArtifactResponseElement(t *testing.T) {
   156  	issueInstant := time.Date(2020, 7, 21, 12, 30, 45, 0, time.UTC)
   157  	status := Status{
   158  		XMLName: xml.Name{
   159  			Space: "urn:oasis:names:tc:SAML:2.0:protocol",
   160  			Local: "Status",
   161  		},
   162  		StatusCode: StatusCode{
   163  			XMLName: xml.Name{
   164  				Space: "urn:oasis:names:tc:SAML:2.0:protocol",
   165  				Local: "StatusCode",
   166  			},
   167  			Value: "value",
   168  		},
   169  	}
   170  	expected := ArtifactResponse{
   171  		ID:           "index",
   172  		InResponseTo: "ID",
   173  		Version:      "version",
   174  		IssueInstant: issueInstant,
   175  		Status:       status,
   176  		Response: Response{
   177  			ID:           "index",
   178  			InResponseTo: "ID",
   179  			Version:      "version",
   180  			Destination:  "destination",
   181  			Consent:      "consent",
   182  			Status:       status,
   183  			IssueInstant: issueInstant,
   184  		},
   185  		// Signature *etree.Element
   186  	}
   187  
   188  	doc := etree.NewDocument()
   189  	doc.SetRoot(expected.Element())
   190  	x, err := doc.WriteToBytes()
   191  	assert.Check(t, err)
   192  	assert.Check(t, is.Equal(`<samlp:ArtifactResponse xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="index" InResponseTo="ID" Version="version" IssueInstant="2020-07-21T12:30:45Z"><samlp:Status><samlp:StatusCode Value="value"/></samlp:Status><samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="index" InResponseTo="ID" Version="version" IssueInstant="2020-07-21T12:30:45Z" Destination="destination" Consent="consent"><samlp:Status><samlp:StatusCode Value="value"/></samlp:Status></samlp:Response></samlp:ArtifactResponse>`,
   193  		string(x)))
   194  
   195  	var actual ArtifactResponse
   196  	err = xml.Unmarshal(x, &actual)
   197  	assert.Check(t, err)
   198  	assert.Check(t, is.DeepEqual(expected, actual))
   199  
   200  	x, err = xml.Marshal(expected)
   201  	assert.Check(t, err)
   202  	assert.Check(t, is.Equal(`<ArtifactResponse xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ID="index" InResponseTo="ID" Version="version" IssueInstant="2020-07-21T12:30:45Z"><Status xmlns="urn:oasis:names:tc:SAML:2.0:protocol"><StatusCode xmlns="urn:oasis:names:tc:SAML:2.0:protocol" Value="value"></StatusCode></Status><Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ID="index" InResponseTo="ID" Version="version" IssueInstant="2020-07-21T12:30:45Z" Destination="destination" Consent="consent"><Status xmlns="urn:oasis:names:tc:SAML:2.0:protocol"><StatusCode xmlns="urn:oasis:names:tc:SAML:2.0:protocol" Value="value"></StatusCode></Status></Response></ArtifactResponse>`,
   203  		string(x)))
   204  }
   205  
   206  func TestLogoutRequestXMLRoundTrip(t *testing.T) {
   207  	issueInstant := time.Date(2021, 10, 8, 12, 30, 0, 0, time.UTC)
   208  	notOnOrAfter := time.Date(2021, 10, 8, 12, 35, 0, 0, time.UTC)
   209  	expected := LogoutRequest{
   210  		ID:           "request-id",
   211  		Version:      "2.0",
   212  		IssueInstant: issueInstant,
   213  		NotOnOrAfter: &notOnOrAfter,
   214  		Issuer: &Issuer{
   215  			XMLName: xml.Name{
   216  				Space: "urn:oasis:names:tc:SAML:2.0:assertion",
   217  				Local: "Issuer",
   218  			},
   219  			Value: "uri:issuer",
   220  		},
   221  		NameID: &NameID{
   222  			Value: "name-id",
   223  		},
   224  		SessionIndex: &SessionIndex{
   225  			Value: "index",
   226  		},
   227  	}
   228  
   229  	doc := etree.NewDocument()
   230  	doc.SetRoot(expected.Element())
   231  	x, err := doc.WriteToBytes()
   232  	assert.Check(t, err)
   233  	assert.Check(t, is.Equal(`<samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="request-id" Version="2.0" IssueInstant="2021-10-08T12:30:00Z" NotOnOrAfter="2021-10-08T12:35:00Z"><saml:Issuer>uri:issuer</saml:Issuer><saml:NameID>name-id</saml:NameID><samlp:SessionIndex xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">index</samlp:SessionIndex></samlp:LogoutRequest>`,
   234  		string(x)))
   235  
   236  	var actual LogoutRequest
   237  	err = xml.Unmarshal(x, &actual)
   238  	assert.Check(t, err)
   239  	assert.Check(t, is.DeepEqual(expected, actual))
   240  
   241  	x, err = xml.Marshal(expected)
   242  	assert.Check(t, err)
   243  	assert.Check(t, is.Equal(`<LogoutRequest xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ID="request-id" Version="2.0" IssueInstant="2021-10-08T12:30:00Z" NotOnOrAfter="2021-10-08T12:35:00Z" Destination=""><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion" NameQualifier="" SPNameQualifier="" Format="" SPProvidedID="">uri:issuer</Issuer><NameID NameQualifier="" SPNameQualifier="" Format="" SPProvidedID="">name-id</NameID><SessionIndex>index</SessionIndex></LogoutRequest>`,
   244  		string(x)))
   245  }
   246  
   247  func TestLogoutRequestMarshalWithoutNotOnOrAfter(t *testing.T) {
   248  	issueInstant := time.Date(2021, 10, 8, 12, 30, 0, 0, time.UTC)
   249  	expected := LogoutRequest{
   250  		ID:           "request-id",
   251  		Version:      "2.0",
   252  		IssueInstant: issueInstant,
   253  		Issuer: &Issuer{
   254  			XMLName: xml.Name{
   255  				Space: "urn:oasis:names:tc:SAML:2.0:assertion",
   256  				Local: "Issuer",
   257  			},
   258  			Value: "uri:issuer",
   259  		},
   260  		NameID: &NameID{
   261  			Value: "name-id",
   262  		},
   263  		SessionIndex: &SessionIndex{
   264  			Value: "index",
   265  		},
   266  	}
   267  
   268  	doc := etree.NewDocument()
   269  	doc.SetRoot(expected.Element())
   270  	x, err := doc.WriteToBytes()
   271  	assert.Check(t, err)
   272  	assert.Check(t, is.Equal(`<samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="request-id" Version="2.0" IssueInstant="2021-10-08T12:30:00Z"><saml:Issuer>uri:issuer</saml:Issuer><saml:NameID>name-id</saml:NameID><samlp:SessionIndex xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">index</samlp:SessionIndex></samlp:LogoutRequest>`,
   273  		string(x)))
   274  
   275  	var actual LogoutRequest
   276  	err = xml.Unmarshal(x, &actual)
   277  	assert.Check(t, err)
   278  	assert.Check(t, is.DeepEqual(expected, actual))
   279  }