-
Notifications
You must be signed in to change notification settings - Fork 4
/
oauth.go
163 lines (137 loc) · 4.08 KB
/
oauth.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
package onelogin
import (
"context"
"errors"
"fmt"
"time"
)
// OauthService handles communications with the authentication related methods on OneLogin.
type OauthService service
type authenticationParams struct {
Username string `json:"username_or_email"`
Password string `json:"password"`
Subdomain string `json:"subdomain"`
}
type issueTokenParams struct {
GrantType string `json:"grant_type"`
AccessToken string `json:"access_token,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
}
type getTokenResponse struct {
AccessToken string `json:"access_token"`
AccountID int `json:"account_id"`
CreatedAt string `json:"created_at"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
}
// An oauthToken authenticates request to OneLogin.
// It is valid for 3600 seconds, and can be renewed.
type oauthToken struct {
AccessToken string
AccountID int
CreatedAt time.Time
ExpiresIn int64
TokenType string
refreshToken string
client *Client
}
// isExpired check the OauthToken validity.
func (t *oauthToken) isExpired() bool {
return time.Now().UTC().Add(-time.Second * time.Duration(t.ExpiresIn)).After(t.CreatedAt.UTC())
}
// refresh the token. The current token gets updates with new valid values.
func (t *oauthToken) refresh(ctx context.Context) error {
u := "/auth/oauth2/token"
b := issueTokenParams{
GrantType: "refresh_token",
AccessToken: t.AccessToken,
RefreshToken: t.refreshToken,
}
req, err := t.client.NewRequest("POST", u, b)
if err != nil {
return err
}
var r []getTokenResponse
_, err = t.client.Do(ctx, req, &r)
if err != nil {
return err
}
createdAt, _ := time.Parse(time.RFC3339Nano, r[0].CreatedAt)
t.AccessToken = r[0].AccessToken
t.AccountID = r[0].AccountID
t.CreatedAt = createdAt
t.ExpiresIn = r[0].ExpiresIn
t.TokenType = r[0].TokenType
t.refreshToken = r[0].RefreshToken
return nil
}
// getToken issues a new token.
func (s *OauthService) getToken(ctx context.Context) (*oauthToken, error) {
u := "/auth/oauth2/token"
b := issueTokenParams{
GrantType: "client_credentials",
}
req, err := s.client.NewRequest("POST", u, b)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", fmt.Sprintf("client_id: %s, client_secret: %s", s.client.clientID, s.client.clientSecret))
var r []getTokenResponse
_, err = s.client.Do(ctx, req, &r)
if err != nil {
return nil, err
}
createdAt, _ := time.Parse(time.RFC3339Nano, r[0].CreatedAt)
token := &oauthToken{
AccessToken: r[0].AccessToken,
AccountID: r[0].AccountID,
CreatedAt: createdAt,
ExpiresIn: r[0].ExpiresIn,
TokenType: r[0].TokenType,
refreshToken: r[0].RefreshToken,
client: s.client,
}
return token, nil
}
type authenticateResponse struct {
Status string `json:"status"`
User *AuthenticatedUser `json:"user"`
ReturnToURL string `json:"return_to_url"`
ExpiresAt string `json:"expires_at"`
SessionToken string `json:"session_token"`
}
// AuthenticatedUser contains user information for the Authentication.
type AuthenticatedUser struct {
ID int64 `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
// Authenticate a user from an email(or username) and a password.
// It returns nil on success.
func (s *OauthService) Authenticate(ctx context.Context, emailOrUsername string, password string) (*AuthenticatedUser, error) {
u := "/api/1/login/auth"
a := authenticationParams{
Username: emailOrUsername,
Password: password,
Subdomain: s.client.subdomain,
}
req, err := s.client.NewRequest("POST", u, a)
if err != nil {
return nil, err
}
if err := s.client.AddAuthorization(ctx, req); err != nil {
return nil, err
}
var d []authenticateResponse
_, err = s.client.Do(ctx, req, &d)
if err != nil {
return nil, err
}
if len(d) != 1 || d[0].Status != "Authenticated" {
return nil, errors.New("authentication failed")
}
return d[0].User, nil
}