summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Wijenbergh <jeroenwijenbergh@protonmail.com>2022-03-21 11:20:34 +0100
committerjwijenbergh <jeroenwijenbergh@protonmail.com>2022-04-05 12:26:16 +0200
commitd45f5df4dc5fa9ad8abdc47c940f6baf96fdbe45 (patch)
treec910ef87fc8464cd93978ce3cda5e3df87a30d5e
parent2d5c7dad599b3f8b70ab07382973c51d1de2193d (diff)
OAuth: Make sure the tokens are not expired
-rw-r--r--cli/main.go2
-rw-r--r--src/api.go11
-rw-r--r--src/oauth.go32
3 files changed, 41 insertions, 4 deletions
diff --git a/cli/main.go b/cli/main.go
index ccec3f4..0bee0c2 100644
--- a/cli/main.go
+++ b/cli/main.go
@@ -50,7 +50,7 @@ func main() {
if oauthErr != nil {
log.Fatal(oauthErr)
}
- infoString, infoErr := state.APIAuthenticatedInfo()
+ infoString, infoErr := state.APIAuthenticatedGet("/info")
if infoErr != nil {
log.Fatal(infoErr)
}
diff --git a/src/api.go b/src/api.go
index 43e92d7..d485728 100644
--- a/src/api.go
+++ b/src/api.go
@@ -4,8 +4,15 @@ import (
"net/http"
)
-func (eduvpn *VPNState) APIAuthenticatedInfo() (string, error) {
- url := eduvpn.Server.Endpoints.API.V3.API + "/info"
+func (eduvpn *VPNState) APIAuthenticatedGet(endpoint string) (string, error) {
+ url := eduvpn.Server.Endpoints.API.V3.API + endpoint
+
+ // Ensure we have non-expired tokens
+ oauthErr := eduvpn.EnsureTokensOAuth()
+
+ if oauthErr != nil {
+ return "", oauthErr
+ }
headers := &http.Header{"Authorization": {"Bearer " + eduvpn.Server.OAuth.Token.Access}}
body, bodyErr := HTTPGetWithOptionalParams(url, &HTTPOptionalParams{Headers: headers})
diff --git a/src/oauth.go b/src/oauth.go
index 80f60d7..bbe34af 100644
--- a/src/oauth.go
+++ b/src/oauth.go
@@ -8,6 +8,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "time"
)
// Generates a random base64 string to be used for state
@@ -73,12 +74,18 @@ type OAuthExchangeSession struct {
Server *http.Server
}
+func generateTimeSeconds() int64 {
+ current := time.Now()
+ return current.Unix()
+}
+
// Struct that defines the json format for /.well-known/vpn-user-portal"
type OAuthToken struct {
Access string `json:"access_token"`
Refresh string `json:"refresh_token"`
Type string `json:"token_type"`
- Expires int `json:"expires_in"`
+ Expires int64 `json:"expires_in"`
+ ExpiredTimestamp int64
}
// Gets an authenticated HTTP client by obtaining refresh and access tokens
@@ -115,6 +122,7 @@ func (oauth *OAuth) getTokensWithAuthCode(authCode string) error {
headers := &http.Header{
"content-type": {"application/x-www-form-urlencoded"}}
opts := &HTTPOptionalParams{Headers: headers}
+ current_time := generateTimeSeconds()
body, bodyErr := HTTPPostWithOptionalParams(reqURL, data, opts)
if bodyErr != nil {
return bodyErr
@@ -127,11 +135,18 @@ func (oauth *OAuth) getTokensWithAuthCode(authCode string) error {
return &HTTPParseJsonError{URL: reqURL, Body: string(body), Err: jsonErr}
}
+ tokenStructure.ExpiredTimestamp = current_time + tokenStructure.Expires
oauth.Token = tokenStructure
return nil
}
+func (oauth *OAuth) isTokensExpired() bool {
+ expired_time := oauth.Token.ExpiredTimestamp
+ current_time := generateTimeSeconds()
+ return current_time >= expired_time
+}
+
// Get the access and refresh tokens with a previously received refresh token
// Access tokens: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-04#section-1.4
// Refresh tokens: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-04#section-1.3.2
@@ -144,6 +159,7 @@ func (oauth *OAuth) getTokensWithRefresh() error {
headers := &http.Header{
"content-type": {"application/x-www-form-urlencoded"}}
opts := &HTTPOptionalParams{Headers: headers}
+ current_time := generateTimeSeconds()
body, bodyErr := HTTPPostWithOptionalParams(reqURL, data, opts)
if bodyErr != nil {
return bodyErr
@@ -156,6 +172,7 @@ func (oauth *OAuth) getTokensWithRefresh() error {
return &HTTPParseJsonError{URL: reqURL, Body: string(body), Err: jsonErr}
}
+ tokenStructure.ExpiredTimestamp = current_time + tokenStructure.Expires
oauth.Token = tokenStructure
return nil
@@ -253,6 +270,19 @@ func (eduvpn *VPNState) FinishOAuth() error {
return oauth.getTokensWithCallback()
}
+func (eduvpn *VPNState) EnsureTokensOAuth() error {
+ oauth := eduvpn.Server.OAuth
+ if oauth == nil {
+ panic("invalid oauth state")
+ }
+
+ if oauth.isTokensExpired() {
+ return oauth.getTokensWithRefresh();
+ }
+ return nil
+}
+
+
type OAuthGenStateUnableError struct {
Err error
}