diff options
| author | Jeroen Wijenbergh <jeroenwijenbergh@protonmail.com> | 2022-03-21 11:20:34 +0100 |
|---|---|---|
| committer | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-04-05 12:26:16 +0200 |
| commit | d45f5df4dc5fa9ad8abdc47c940f6baf96fdbe45 (patch) | |
| tree | c910ef87fc8464cd93978ce3cda5e3df87a30d5e | |
| parent | 2d5c7dad599b3f8b70ab07382973c51d1de2193d (diff) | |
OAuth: Make sure the tokens are not expired
| -rw-r--r-- | cli/main.go | 2 | ||||
| -rw-r--r-- | src/api.go | 11 | ||||
| -rw-r--r-- | src/oauth.go | 32 |
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) } @@ -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 } |
