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: ¬OnOrAfter, 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 }