Skip to content

Commit

Permalink
work on the claim verification in the auth package
Browse files Browse the repository at this point in the history
  • Loading branch information
RabbITCybErSeC committed Oct 2, 2024
1 parent ae0885f commit e9830ba
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 5 deletions.
31 changes: 29 additions & 2 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,25 @@ const (
COOKIE_SECRET_KEY_LENGHT = 32
)

type User struct {
Username string `json:"username"`
Email string `json:"email"`
Name string `json:"name"`
Groups []string `json:"groups"`
}
type UserClaimsConfig struct {
OIDCClaimUsernameField string
OIDCClaimEmailField string
OIDCClaimNameField string
OIDCClaimGroupsField string
}

type Authenticator struct {
Cookiejar cookies.ICookieJar
OIDCconfig *oidc.Config
OauthConfig *oauth2.Config
verifierProvider *oidc.Provider
userclaimConfig *UserClaimsConfig
skipTLSVerify bool
}

Expand Down Expand Up @@ -72,10 +86,22 @@ func SetupOIDCAuthHandler() *Authenticator {
Endpoint: provider.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
userClaimsConfig := &UserClaimsConfig{
OIDCClaimUsernameField: "preferred_username",
OIDCClaimEmailField: "email",
OIDCClaimNameField: "name",
OIDCClaimGroupsField: "groups",
}

cookieJar := cookies.NewCookieJar([]byte(env.cookieJarSecret), []byte(env.cookieEncryptionKey))

return NewAuthenticator(cookieJar, oidcConfig, oauthConfig, provider, skipTLS)
return NewAuthenticator(
cookieJar,
oidcConfig,
oauthConfig,
provider,
skipTLS,
userClaimsConfig)
}

func validateEnvVariables(env struct {
Expand Down Expand Up @@ -111,12 +137,13 @@ func setupHTTPClient(skipTLS bool) *http.Client {
return http.DefaultClient
}

func NewAuthenticator(cj cookies.ICookieJar, OIDCconfig *oidc.Config, OauthConfig *oauth2.Config, verifierProvider *oidc.Provider, skipTLSVerify bool) *Authenticator {
func NewAuthenticator(cj cookies.ICookieJar, OIDCconfig *oidc.Config, OauthConfig *oauth2.Config, verifierProvider *oidc.Provider, skipTLSVerify bool, userClaims *UserClaimsConfig) *Authenticator {
return &Authenticator{
Cookiejar: cj,
OIDCconfig: OIDCconfig,
OauthConfig: OauthConfig,
verifierProvider: verifierProvider,
userclaimConfig: userClaims,
skipTLSVerify: skipTLSVerify,
}
}
Expand Down
5 changes: 5 additions & 0 deletions auth/cookies/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type ICookieJar interface {
SetCallBackState(context *gin.Context, stateValue string) error
GetStateSession(context *gin.Context) (value string, isNew bool)
GetNonceSession(context *gin.Context) (value string, isNew bool)
GetUserToken(context *gin.Context) (value string, isNew bool)
SetUserToken(context *gin.Context, token string) error
DeleteStateSession(context *gin.Context) error
DeleteNonceSession(context *gin.Context) error
Expand Down Expand Up @@ -44,6 +45,10 @@ func (cj *CookieJar) GetNonceSession(context *gin.Context) (value string, isNew
return cj.getStateSession(context, CALLBACK_NONCE)
}

func (cj *CookieJar) GetUserToken(context *gin.Context) (value string, isNew bool) {
return cj.getStateSession(context, CALLBACK_NONCE)
}

func (cj *CookieJar) SetUserToken(context *gin.Context, token string) error {
session := sessions.NewSession(cj.store, USER_TOKEN)
session.Values["token"] = token
Expand Down
7 changes: 6 additions & 1 deletion auth/gin_oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ func (auth *Authenticator) OIDCCallBack(gc *gin.Context) {

func (auth *Authenticator) sessionAuth(gc *gin.Context) gin.HandlerFunc {
return func(gc *gin.Context) {
return
tokenCookie, noCookie := auth.Cookiejar.GetUserToken(gc)
if noCookie {
gc.Redirect(http.StatusOK, "/")
return
}
username, role, err := auth.VerifyClaims(gc*gin.Context, tokenCookie)

Check failure on line 93 in auth/gin_oidc.go

View workflow job for this annotation

GitHub Actions / Run ci-tests

declared and not used: username

Check failure on line 93 in auth/gin_oidc.go

View workflow job for this annotation

GitHub Actions / Run ci-tests

declared and not used: role

Check failure on line 93 in auth/gin_oidc.go

View workflow job for this annotation

GitHub Actions / Run ci-tests

declared and not used: err

Check failure on line 93 in auth/gin_oidc.go

View workflow job for this annotation

GitHub Actions / Run ci-tests

gin.Context (type) is not an expression
}
}
1 change: 0 additions & 1 deletion auth/jwt.go

This file was deleted.

47 changes: 47 additions & 0 deletions auth/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package auth

import (
"errors"
"fmt"

"github.com/gin-gonic/gin"
)

func (auth *Authenticator) VerifyClaims(gc *gin.Context, token string) (name string, role string, err error) {
verifier := auth.GetTokenVerifier()
accessToken, err := verifier.Verify(gc, token)
if err != nil {
return "", "", errors.New(fmt.Sprintf("could not obtain token from cookie: %w", err))
}
var claims map[string]any
if err := accessToken.Claims(&claims); err != nil {
return "", "", errors.New(fmt.Sprintf("could not map clains: %w", err))
}
if _, ok := claims["iss"]; !ok {
return "", "", errors.New("no issues in claim")
}

return "", "", nil
}

func (auth *Authenticator) mapClaimsToUser(claims map[string]any) (*User, error) {
user := &User{}

if username, ok := claims[auth.userclaimConfig.OIDCClaimUsernameField].(string); ok {
user.Username = username
}
if email, ok := claims[auth.userclaimConfig.OIDCClaimEmailField].(string); ok {
user.Email = email
}
if name, ok := claims[auth.userclaimConfig.OIDCClaimNameField].(string); ok {
user.Name = name
}
if groups, ok := claims[auth.userclaimConfig.OIDCClaimGroupsField].([]interface{}); ok {
user.Groups = make([]string, len(groups))
for i, g := range groups {
user.Groups[i] = g.(string)
}
}

return user, nil
}
37 changes: 37 additions & 0 deletions auth/verify_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package auth

import (
"testing"

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

func TestMapClaimsToUser_AllFieldsMappedCorrectly(t *testing.T) {
UserClaimsConfig := UserClaimsConfig{
OIDCClaimUsernameField: "preferred_username",
OIDCClaimEmailField: "email",
OIDCClaimNameField: "name",
OIDCClaimGroupsField: "groups",
}
claims := map[string]interface{}{
"preferred_username": "johndoe",
"email": "[email protected]",
"name": "John Doe",
"groups": []interface{}{"users", "admins"},
}
expectedUser := &User{
Username: "johndoe",
Email: "[email protected]",
Name: "John Doe",
Groups: []string{"users", "admins"},
}

auth := &Authenticator{
userclaimConfig: &UserClaimsConfig,
}

user, err := auth.mapClaimsToUser(claims)

assert.NoError(t, err)
assert.Equal(t, expectedUser, user)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/a-h/templ v0.2.771
github.com/coreos/go-oidc/v3 v3.11.0
github.com/gin-gonic/gin v1.10.0
github.com/gorilla/securecookie v1.1.2
github.com/gorilla/sessions v1.4.0
github.com/stretchr/testify v1.9.0
golang.org/x/oauth2 v0.21.0
Expand All @@ -16,7 +17,6 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)

Expand Down

0 comments on commit e9830ba

Please sign in to comment.