Skip to content
This repository has been archived by the owner on Jan 20, 2023. It is now read-only.

add raw token parsing function #41

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion vmidentity/goclients/oidc/oidcclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package oidc
import (
"crypto/rsa"
"crypto/x509"
"gopkg.in/square/go-jose.v2"
"time"

jose "gopkg.in/square/go-jose.v2"
)

// Client represents an oidc client
Expand Down Expand Up @@ -73,6 +74,12 @@ func ParseTenantInToken(token string) (string, error) {
return parseTenantInToken(token)
}

// ParseSignedToken parses a token string and returns an unvalidated JWT.
func ParseSignedToken(token string) (JWT, error) {
jwt, err := parseSignedToken(token, nil)
return jwt, err
}

// Tokens represents successful acquire token response
type Tokens interface {
AccessToken() string
Expand Down
41 changes: 25 additions & 16 deletions vmidentity/goclients/oidc/token_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"gopkg.in/square/go-jose.v2"
"strings"
"time"

jose "gopkg.in/square/go-jose.v2"
)

const (
Expand Down Expand Up @@ -44,8 +45,8 @@ const (
IDTokenClass = "id_token"
)

// jwt interface represents a parsed/validated jwt
type jwt interface {
// JWT interface represents a parsed/validated JWT
type JWT interface {
Issuer() string
Nonce() (string, bool)
Groups() ([]string, bool)
Expand Down Expand Up @@ -91,7 +92,7 @@ func parseTenantInToken(token string) (string, error) {
}

func parseToken(
token string, issuer string, audience string, nonce string, signers IssuerSigners, tokenType string, logger Logger) (jwt, error) {
token string, issuer string, audience string, nonce string, signers IssuerSigners, tokenType string, logger Logger) (JWT, error) {
var err error

if signers == nil {
Expand Down Expand Up @@ -128,8 +129,8 @@ func parseToken(
}

func verifyToken(token string, signers *jose.JSONWebKeySet, issuer string, audience string, nonce string,
clockTolerance int, logger Logger) (jwt, error) {
jwt, err := parseSignedToken(token, issuer, signers, clockTolerance)
clockTolerance int, logger Logger) (JWT, error) {
jwt, err := parseAndValidateSignedToken(token, issuer, signers, clockTolerance)

if err != nil {
PrintLog(logger, LogLevelError, "verifyToken: Parse signed token failed. Error: '%v'", err)
Expand Down Expand Up @@ -484,7 +485,22 @@ type jwtImpl struct {
}

// parseSignedToken parses jwt token from its string representation
func parseSignedToken(token string, issuer string, keySet *jose.JSONWebKeySet, clockToleranceSecs int) (jwt, error) {
func parseAndValidateSignedToken(token string, issuer string, keySet *jose.JSONWebKeySet, clockToleranceSecs int) (JWT, error) {
jwt, err := parseSignedToken(token, keySet)
if err != nil {
return nil, err
}
jwti := jwt.(*jwtImpl)
// validate and normalize expected claims.
err = validateAndNormalizeClaims(&jwti.claims, issuer, clockToleranceSecs)
if err != nil {
return nil, err
}
return jwt, nil
}

// parseSignedToken parses jwt token from its string representation
func parseSignedToken(token string, keySet *jose.JSONWebKeySet) (JWT, error) {
jws, err := jose.ParseSigned(token)
if err != nil {
return nil, OIDCTokenInvalidError.MakeError("Token format is invalid", err)
Expand Down Expand Up @@ -522,13 +538,6 @@ func parseSignedToken(token string, issuer string, keySet *jose.JSONWebKeySet, c
if err != nil {
return nil, err
}

// validate and normalize expected claims.
err = validateAndNormalizeClaims(&tokenBody, issuer, clockToleranceSecs)
if err != nil {
return nil, err
}

return &jwtImpl{claims: tokenBody}, nil
}

Expand Down Expand Up @@ -672,8 +681,8 @@ func decodePayload(payload []byte) (map[string]interface{}, error) {
}

func parseTokenMulti(
token string, audience string, nonce string, providerInfo []ProviderInfo, tokenType string, logger Logger) (jwt, int, error) {
var tok jwt
token string, audience string, nonce string, providerInfo []ProviderInfo, tokenType string, logger Logger) (JWT, int, error) {
var tok JWT
var index int
var err error
var info ProviderInfo
Expand Down
19 changes: 10 additions & 9 deletions vmidentity/goclients/oidc/token_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package oidc

import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestValidateExpiration(t *testing.T) {
Expand Down Expand Up @@ -61,13 +62,13 @@ func TestValidateAudienceClaim(t *testing.T) {

func TestParseSignedToken(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwic3ViIjoic3ViSjEiLCJuYmYiOjE1MjE3NzMwOTgsImV4cCI6MTUyMTc3NjY5OCwiaWF0IjoxNTIxNzczMDk4LCJqdGkiOiJpZDEyMzQ1NiJ9.wf8E82CGm_saE8gGnoz7aX1COSzkc5ZbcO2H7xJSgIQ"
jwt, err := parseSignedToken(token, "issuer1", nil, defaultClockToleranceSecs)
jwt, err := parseAndValidateSignedToken(token, "issuer1", nil, defaultClockToleranceSecs)
assert.Nil(t, jwt, "Token should be nil")
if assert.NotNil(t, err, "Error is expected when using unsupported signature algo") {
assert.Contains(t, err.Error(), OIDCTokenInvalidError.Name())
}

jwt, err = parseSignedToken("", "issuer1", nil, defaultClockToleranceSecs)
jwt, err = parseAndValidateSignedToken("", "issuer1", nil, defaultClockToleranceSecs)
assert.Nil(t, jwt, "Token should be nil")
if assert.NotNil(t, err, "Error is expected when using bad token") {
assert.Contains(t, err.Error(), OIDCTokenInvalidError.Name())
Expand All @@ -85,21 +86,21 @@ func TestParseSignedToken(t *testing.T) {
require.True(t, ok, "Error when getting keyset from IssuerSigners")
require.NotNil(t, s, "KeySet is nil")

jwt, err = parseSignedToken(strTok, client.Issuer(), s.signers, defaultClockToleranceSecs)
jwt, err = parseAndValidateSignedToken(strTok, client.Issuer(), s.signers, defaultClockToleranceSecs)
assert.Nil(t, err, "No error expected: %+v", err)
assert.NotNil(t, jwt, "Token should not be nil")

jwt, err = parseSignedToken(" "+strTok+" ", client.Issuer(), s.signers, defaultClockToleranceSecs)
jwt, err = parseAndValidateSignedToken(" "+strTok+" ", client.Issuer(), s.signers, defaultClockToleranceSecs)
assert.Nil(t, err, "No error expected: %+v", err)
assert.NotNil(t, jwt, "Token should not be nil")

jwt, err = parseSignedToken(strTok+"a", client.Issuer(), s.signers, defaultClockToleranceSecs)
jwt, err = parseAndValidateSignedToken(strTok+"a", client.Issuer(), s.signers, defaultClockToleranceSecs)
if assert.NotNil(t, err, "Error expected when parsing malformed token") {
assert.Contains(t, err.Error(), OIDCTokenInvalidSignatureError.Name(), "Wrong Error code: %+v", err)
}
assert.Nil(t, jwt, "No token expected")

jwt, err = parseSignedToken(strTok, "wrongIssuer", s.signers, defaultClockToleranceSecs)
jwt, err = parseAndValidateSignedToken(strTok, "wrongIssuer", s.signers, defaultClockToleranceSecs)
if assert.NotNil(t, err, "Error expected when token from incorrect issuer") {
assert.Contains(t, err.Error(), OIDCTokenInvalidError.Name(), "Wrong Error code: %+v", err)
}
Expand Down Expand Up @@ -147,7 +148,7 @@ func TestParseHotkClaim(t *testing.T) {
func testInvalidTokens(t *testing.T, token string) {
testInvalidTenantInToken(t, token)

jwt, err := parseSignedToken(token, "issuer1", nil, defaultClockToleranceSecs)
jwt, err := parseAndValidateSignedToken(token, "issuer1", nil, defaultClockToleranceSecs)
assert.Nil(t, jwt, "Token should be nil")
if assert.NotNil(t, err, "Error is expected when using bad token") {
assert.Contains(t, err.Error(), OIDCTokenInvalidError.Name())
Expand Down