-
Notifications
You must be signed in to change notification settings - Fork 0
/
stsresponse.go
108 lines (85 loc) · 3.42 KB
/
stsresponse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package stsclient
import (
"net/http"
"io/ioutil"
"fmt"
"strings"
etree "github.com/beevik/etree"
)
type StsResponse struct {
assertion string
}
func ParseStsResponse(response *http.Response) (*StsResponse, error) {
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if (err != nil) {
return nil, err
}
if (response.StatusCode != http.StatusOK) {
fmt.Errorf("Response not OK (payload: %s)", body)
}
assertion, err := HandleStsResponsePayload(body)
if (err != nil) {
return nil, err
}
stsResponse := &StsResponse{ assertion: assertion }
return stsResponse, nil
}
func HandleStsResponsePayload(payload []byte) (string, error) {
responseDocument := etree.NewDocument()
if err := responseDocument.ReadFromBytes(payload); err != nil {
return "", err
}
// The root node must be the SOAP Envelope
rootElement := responseDocument.Root()
bodyXPathExpression := "/Envelope/Body" // If soap is the default namespace
hasNameSpace, soapNamespace, _ := splitNameSpaceAndTag(rootElement)
if (hasNameSpace) {
bodyXPathExpression = fmt.Sprintf("/%s:Envelope/%s:Body", soapNamespace, soapNamespace)
}
bodyQueryResult := rootElement.FindElements(bodyXPathExpression)
if (len(bodyQueryResult) != 1) {
return "", fmt.Errorf("No body element found in STS response (response payload: %s)", string(payload))
}
bodyElement := bodyQueryResult[0]
// Now let's look further down
bodyChildren := bodyElement.ChildElements()
if (len(bodyChildren) != 1) {
return "", fmt.Errorf("Exactly one child element expected for the body")
}
requestTokenResponseCollectionElement := bodyChildren[0]
requestedSecurityTokenXPathExpression := "RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse/RequestedSecurityToken"
hasNameSpace, trustNamespace, _ := splitNameSpaceAndTag(requestTokenResponseCollectionElement)
if (hasNameSpace) {
requestedSecurityTokenXPathExpression = fmt.Sprintf("/%s:RequestSecurityTokenResponseCollection/%s:RequestSecurityTokenResponse/%s:RequestedSecurityToken", trustNamespace, trustNamespace, trustNamespace)
}
requestedSecurityTokenQueryResult := bodyElement.FindElements(requestedSecurityTokenXPathExpression)
if (len(requestedSecurityTokenQueryResult) != 1) {
return "", fmt.Errorf("No RequestedSecurityToken under the body element found in STS response (response payload: %s)", string(payload))
}
requestedSecurityTokenElement := requestedSecurityTokenQueryResult[0]
// We expect exactly one child...and that is the assertion
requestedSecurityTokenElementChildren := requestedSecurityTokenElement.ChildElements()
if (len(requestedSecurityTokenElementChildren) != 1) {
return "", fmt.Errorf("Exactly one child element expected for the RequestedSecurityToken")
}
assertionElement := requestedSecurityTokenElementChildren[0]
// Copy the assertionElement from the response to create a new document
assertionDocument := etree.NewDocument()
assertionDocument.SetRoot(assertionElement.Copy())
assertionStr, err := assertionDocument.WriteToString()
if (err != nil) {
return "", err
}
return assertionStr, nil
}
func splitNameSpaceAndTag(element *etree.Element) (bool, string, string) {
elementTagSlice := strings.Split(element.Tag, ":")
if (len(elementTagSlice) == 2) {
return true, elementTagSlice[0], elementTagSlice[1]
}
return false, "", element.Tag
}
func (resp *StsResponse) ToString() string {
return resp.assertion
}