-
Notifications
You must be signed in to change notification settings - Fork 96
/
service_validate.go
183 lines (143 loc) · 4.18 KB
/
service_validate.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package cas
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"github.com/golang/glog"
)
// NewServiceTicketValidator create a new *ServiceTicketValidator
func NewServiceTicketValidator(client *http.Client, casURL *url.URL) *ServiceTicketValidator {
return &ServiceTicketValidator{
client: client,
casURL: casURL,
}
}
// ServiceTicketValidator is responsible for the validation of a service ticket
type ServiceTicketValidator struct {
client *http.Client
casURL *url.URL
}
// ValidateTicket validates the service ticket for the given server. The method will try to use the service validate
// endpoint of the cas >= 2 protocol, if the service validate endpoint not available, the function will use the cas 1
// validate endpoint.
func (validator *ServiceTicketValidator) ValidateTicket(serviceURL *url.URL, ticket string) (*AuthenticationResponse, error) {
if glog.V(2) {
glog.Infof("Validating ticket %v for service %v", ticket, serviceURL)
}
u, err := validator.ServiceValidateUrl(serviceURL, ticket)
if err != nil {
return nil, err
}
r, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
r.Header.Add("User-Agent", "Golang CAS client gopkg.in/cas")
if glog.V(2) {
glog.Infof("Attempting ticket validation with %v", r.URL)
}
resp, err := validator.client.Do(r)
if err != nil {
return nil, err
}
if glog.V(2) {
glog.Infof("Request %v %v returned %v",
r.Method, r.URL,
resp.Status)
}
if resp.StatusCode == http.StatusNotFound {
return validator.validateTicketCas1(serviceURL, ticket)
}
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("cas: validate ticket: %v", string(body))
}
if glog.V(2) {
glog.Infof("Received authentication response\n%v", string(body))
}
success, err := ParseServiceResponse(body)
if err != nil {
return nil, err
}
if glog.V(2) {
glog.Infof("Parsed ServiceResponse: %#v", success)
}
return success, nil
}
// ServiceValidateUrl creates the service validation url for the cas >= 2 protocol.
// TODO the function is only exposed, because of the clients ServiceValidateUrl function
func (validator *ServiceTicketValidator) ServiceValidateUrl(serviceURL *url.URL, ticket string) (string, error) {
u, err := validator.casURL.Parse(path.Join(validator.casURL.Path, "serviceValidate"))
if err != nil {
return "", err
}
q := u.Query()
q.Add("service", sanitisedURLString(serviceURL))
q.Add("ticket", ticket)
u.RawQuery = q.Encode()
return u.String(), nil
}
func (validator *ServiceTicketValidator) validateTicketCas1(serviceURL *url.URL, ticket string) (*AuthenticationResponse, error) {
u, err := validator.ValidateUrl(serviceURL, ticket)
if err != nil {
return nil, err
}
r, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
r.Header.Add("User-Agent", "Golang CAS client gopkg.in/cas")
if glog.V(2) {
glog.Infof("Attempting ticket validation with %v", r.URL)
}
resp, err := validator.client.Do(r)
if err != nil {
return nil, err
}
if glog.V(2) {
glog.Infof("Request %v %v returned %v",
r.Method, r.URL,
resp.Status)
}
data, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, err
}
body := string(data)
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("cas: validate ticket: %v", body)
}
if glog.V(2) {
glog.Infof("Received authentication response\n%v", body)
}
if body == "no\n\n" {
return nil, nil // not logged in
}
success := &AuthenticationResponse{
User: body[4 : len(body)-1],
}
if glog.V(2) {
glog.Infof("Parsed ServiceResponse: %#v", success)
}
return success, nil
}
// ValidateUrl creates the validation url for the cas >= 1 protocol.
// TODO the function is only exposed, because of the clients ValidateUrl function
func (validator *ServiceTicketValidator) ValidateUrl(serviceURL *url.URL, ticket string) (string, error) {
u, err := validator.casURL.Parse(path.Join(validator.casURL.Path, "validate"))
if err != nil {
return "", err
}
q := u.Query()
q.Add("service", sanitisedURLString(serviceURL))
q.Add("ticket", ticket)
u.RawQuery = q.Encode()
return u.String(), nil
}