-
-
Notifications
You must be signed in to change notification settings - Fork 141
/
login.go
146 lines (137 loc) · 4.95 KB
/
login.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
package oauth1
import (
"net/http"
"github.com/dghubble/gologin/v2"
"github.com/dghubble/gologin/v2/internal"
"github.com/dghubble/oauth1"
)
// LoginHandler handles OAuth1 login requests by obtaining a request token and
// secret (temporary credentials) and adding it to the ctx. If successful,
// handling delegates to the success handler, otherwise to the failure handler.
//
// Typically, the success handler is an AuthRedirectHandler or a handler which
// stores the request token secret.
func LoginHandler(config *oauth1.Config, success, failure http.Handler) http.Handler {
if failure == nil {
failure = gologin.DefaultFailureHandler
}
fn := func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
requestToken, requestSecret, err := config.RequestToken()
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
ctx = WithRequestToken(ctx, requestToken, requestSecret)
success.ServeHTTP(w, req.WithContext(ctx))
}
return http.HandlerFunc(fn)
}
// AuthRedirectHandler reads the request token from the ctx and redirects
// to the authorization URL.
func AuthRedirectHandler(config *oauth1.Config, failure http.Handler) http.Handler {
if failure == nil {
failure = gologin.DefaultFailureHandler
}
fn := func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
requestToken, _, err := RequestTokenFromContext(ctx)
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
authorizationURL, err := config.AuthorizationURL(requestToken)
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
http.Redirect(w, req, authorizationURL.String(), http.StatusFound)
}
return http.HandlerFunc(fn)
}
// CookieTempHandler persists or retrieves the request token secret (temporary
// credentials). If the request token can be read from the ctx (login phase),
// the secret is set in a short-lived cookie to be read later. Otherwise
// (callback phase) the cookie is read to retrieve the request token secret
// and add it to the ctx.
// If the ctx contains no request token and the request has no temp cookie,
// the failure handler is called.
//
// Some OAuth1 providers (Twitter, Digits) do NOT require temp secrets to be
// kept between the login phase and callback phase. To implement those
// providers, use the EmptyTempHandler instead.
func CookieTempHandler(config gologin.CookieConfig, success, failure http.Handler) http.Handler {
if failure == nil {
failure = gologin.DefaultFailureHandler
}
fn := func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
_, requestSecret, err := RequestTokenFromContext(ctx)
if err == nil {
// add request secret to a short-lived cookie
http.SetCookie(w, internal.NewCookie(config, requestSecret))
success.ServeHTTP(w, req.WithContext(ctx))
return
}
// read request secret from the short-lived cookie to add to ctx
cookie, err := req.Cookie(config.Name)
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
ctx = WithRequestToken(ctx, "", cookie.Value)
success.ServeHTTP(w, req.WithContext(ctx))
}
return http.HandlerFunc(fn)
}
// EmptyTempHandler adds an empty request token secret to the ctx if none is
// present to support OAuth1 providers which do not require temp secrets to
// be kept between the login phase and callback phase.
func EmptyTempHandler(success http.Handler) http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
_, _, err := RequestTokenFromContext(ctx)
if err != nil {
ctx = WithRequestToken(ctx, "", "")
}
success.ServeHTTP(w, req.WithContext(ctx))
}
return http.HandlerFunc(fn)
}
// CallbackHandler handles OAuth1 callback requests by parsing the oauth token
// and verifier, reading the request token secret from the ctx, then obtaining
// an access token and adding it to the ctx.
func CallbackHandler(config *oauth1.Config, success, failure http.Handler) http.Handler {
if failure == nil {
failure = gologin.DefaultFailureHandler
}
fn := func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
requestToken, verifier, err := oauth1.ParseAuthorizationCallback(req)
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
// upstream handler should add the request token secret from the login step
_, requestSecret, err := RequestTokenFromContext(ctx)
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
accessToken, accessSecret, err := config.AccessToken(requestToken, requestSecret, verifier)
if err != nil {
ctx = gologin.WithError(ctx, err)
failure.ServeHTTP(w, req.WithContext(ctx))
return
}
ctx = WithAccessToken(ctx, accessToken, accessSecret)
success.ServeHTTP(w, req.WithContext(ctx))
}
return http.HandlerFunc(fn)
}