forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
grant.go
133 lines (111 loc) · 4.26 KB
/
grant.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
package handlers
import (
"errors"
"net/http"
"net/url"
"github.com/RangelReale/osin"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
"github.com/openshift/origin/pkg/auth/api"
)
// GrantCheck implements osinserver.AuthorizeHandler to ensure requested scopes have been authorized
type GrantCheck struct {
check GrantChecker
handler GrantHandler
errorHandler GrantErrorHandler
}
// NewGrantCheck returns a new GrantCheck
func NewGrantCheck(check GrantChecker, handler GrantHandler, errorHandler GrantErrorHandler) *GrantCheck {
return &GrantCheck{check, handler, errorHandler}
}
// HandleAuthorize implements osinserver.AuthorizeHandler to ensure the requested scopes have been authorized.
// The AuthorizeRequest.Authorized field must already be set to true for the grant check to occur.
// If the requested scopes are authorized, the AuthorizeRequest is unchanged.
// If the requested scopes are not authorized, or an error occurs, AuthorizeRequest.Authorized is set to false.
// If the response is written, true is returned.
// If the response is not written, false is returned.
func (h *GrantCheck) HandleAuthorize(ar *osin.AuthorizeRequest, w http.ResponseWriter) (bool, error) {
// Requests must already be authorized before we will check grants
if !ar.Authorized {
return false, nil
}
// Reset request to unauthorized until we verify the grant
ar.Authorized = false
user, ok := ar.UserData.(user.Info)
if !ok || user == nil {
return h.errorHandler.GrantError(errors.New("the provided user data is not user.Info"), w, ar.HttpRequest)
}
grant := &api.Grant{
Client: ar.Client,
Scope: ar.Scope,
Expiration: int64(ar.Expiration),
RedirectURI: ar.RedirectUri,
}
// Check if the user has already authorized this grant
authorized, err := h.check.HasAuthorizedClient(user, grant)
if err != nil {
return h.errorHandler.GrantError(err, w, ar.HttpRequest)
}
if authorized {
ar.Authorized = true
return false, nil
}
// React to an unauthorized grant
authorized, handled, err := h.handler.GrantNeeded(user, grant, w, ar.HttpRequest)
if authorized {
ar.Authorized = true
}
return handled, err
}
type emptyGrant struct{}
// NewEmptyGrant returns a no-op grant handler
func NewEmptyGrant() GrantHandler {
return emptyGrant{}
}
// GrantNeeded implements the GrantHandler interface
func (emptyGrant) GrantNeeded(user user.Info, grant *api.Grant, w http.ResponseWriter, req *http.Request) (bool, bool, error) {
return false, false, nil
}
type autoGrant struct {
}
// NewAutoGrant returns a grant handler that automatically approves client authorizations
func NewAutoGrant() GrantHandler {
return &autoGrant{}
}
// GrantNeeded implements the GrantHandler interface
func (g *autoGrant) GrantNeeded(user user.Info, grant *api.Grant, w http.ResponseWriter, req *http.Request) (bool, bool, error) {
return true, false, nil
}
type redirectGrant struct {
url string
}
// If a user denies a grant, a grant handler can return control to the /authorize handler with an error=grant_denied parameter
// and the denial will be returned to the client, rather than re-calling GrantNeeded
const GrantDeniedError = "grant_denied"
// NewRedirectGrant returns a grant handler that redirects to the given URL when a grant is needed.
// The following query parameters are added to the URL:
// then - original request URL
// client_id - requesting client's ID
// scopes - grant scope requested
// redirect_uri - original authorize request redirect_uri
func NewRedirectGrant(url string) GrantHandler {
return &redirectGrant{url}
}
// GrantNeeded implements the GrantHandler interface
func (g *redirectGrant) GrantNeeded(user user.Info, grant *api.Grant, w http.ResponseWriter, req *http.Request) (bool, bool, error) {
// If the current request has an error=grant_denied parameter, the user denied the grant
if err := req.FormValue("error"); err == GrantDeniedError {
return false, false, nil
}
redirectURL, err := url.Parse(g.url)
if err != nil {
return false, false, err
}
redirectURL.RawQuery = url.Values{
"then": {req.URL.String()},
"client_id": {grant.Client.GetId()},
"scopes": {grant.Scope},
"redirect_uri": {grant.RedirectURI},
}.Encode()
http.Redirect(w, req, redirectURL.String(), http.StatusFound)
return false, true, nil
}