Skip to content

Commit

Permalink
wip on callback function
Browse files Browse the repository at this point in the history
  • Loading branch information
RabbITCybErSeC committed Sep 22, 2024
1 parent bc4c2aa commit 6038fe6
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 14 deletions.
4 changes: 2 additions & 2 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,6 @@ func NewAuthenticator(cj cookies.ICookieJar, OIDCconfig *oidc.Config, OauthConfi
return &Authenticator{Cookiejar: cj, OIDCconfig: OIDCconfig, OauthConfig: OauthConfig, verifierProvider: verifierProvider}
}

func (auth *Authenticator) GetVerifier() *oidc.Provider {
return auth.verifierProvider
func (auth *Authenticator) GetTokenVerifier() *oidc.IDTokenVerifier {
return auth.verifierProvider.Verifier(auth.OIDCconfig)
}
24 changes: 20 additions & 4 deletions auth/cookies/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
)

type ICookieJar interface {
SetCallBackCookie(*gin.Context, string, string)
SetCallBackState(context *gin.Context, name string, stateValue string)
StateSession(contex *gin.Context, name string) (value string, isNew bool)
}
type CookieJar struct {
store sessions.Store
Expand All @@ -18,15 +19,30 @@ func NewCookieJar(secret []byte) *CookieJar {
return &CookieJar{store: sessions.NewCookieStore(secret)}
}

func (cj *CookieJar) SetCallBackCookie(g *gin.Context, name string, stateValue string) {
func (cj *CookieJar) SetCallBackState(context *gin.Context, name string, stateValue string) {
session := sessions.NewSession(cj.store, name)
session.Values["state"] = stateValue
session.Options.MaxAge = 60 * 5
session.Options.Path = "/"
session.Options.Secure = g.Request.TLS != nil
session.Options.Secure = context.Request.TLS != nil

if err := cj.store.Save(g.Request, g.Writer, session); err != nil {
if err := cj.store.Save(context.Request, context.Writer, session); err != nil {
fmt.Println("[error] failed to store session")
return
}
}

func (cj *CookieJar) StateSession(context *gin.Context, stateValue string) (value string, isNew bool) {
session, _ := cj.store.Get(context.Request, stateValue)

if session.IsNew {
return "", true
}

state, ok := session.Values["state"].(string)
if ok {
return state, false
}

return "", true
}
54 changes: 51 additions & 3 deletions auth/gin_oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
CALLBACK_NONCE = "soarca_gui_nonce"
)

func (auth *Authenticator) RedirectToOIDCLogin(context *gin.Context) {
func (auth *Authenticator) OIDCRedirectToLogin(context *gin.Context) {
state, err := randString(32)
if err != nil {
api.JSONErrorStatus(context, http.StatusInsufficientStorage, errors.New("failed to generate state"))
Expand All @@ -25,8 +25,56 @@ func (auth *Authenticator) RedirectToOIDCLogin(context *gin.Context) {
api.JSONErrorStatus(context, http.StatusInsufficientStorage, errors.New("failed to generate nonce"))
return
}
auth.Cookiejar.SetCallBackCookie(context, CALLBACK_STATE, state)
auth.Cookiejar.SetCallBackCookie(context, CALLBACK_NONCE, nonce)
auth.Cookiejar.SetCallBackState(context, CALLBACK_STATE, state)
auth.Cookiejar.SetCallBackState(context, CALLBACK_NONCE, nonce)

context.Redirect(http.StatusFound, auth.OauthConfig.AuthCodeURL(state, oidc.Nonce(nonce)))
}

func (auth *Authenticator) OIDCCallBack(context *gin.Context) {
state, isNew := auth.Cookiejar.StateSession(context, CALLBACK_STATE)
if isNew || state == "" {
api.JSONErrorStatus(context, http.StatusInternalServerError, errors.New("state missing"))
return
}

cookie, err := context.Request.Cookie(CALLBACK_STATE)
if err != nil {
api.JSONErrorStatus(context, http.StatusBadRequest, errors.New("state missing from client"))
return
}

if cookie.Value != state {
api.JSONErrorStatus(context, http.StatusUnauthorized, errors.New("state mismatch"))
return
}

oauth2Token, err := auth.OauthConfig.Exchange(context, context.Query("code"))
if err != nil {
api.JSONErrorStatus(context, http.StatusBadRequest, errors.New("could not get code from URL"))
return
}
rawIDtoken, ok := oauth2Token.Extra("id_token").(string)

if !ok {
api.JSONErrorStatus(context, http.StatusBadRequest, errors.New("could not obtain code from URL"))
return
}

verifier := auth.GetTokenVerifier()
verifiedIDToken, err := verifier.Verify(context, rawIDtoken)
if err != nil {
api.JSONErrorStatus(context, http.StatusInternalServerError, errors.New("failed to verify ID token"))
return
}

nonce, err := context.Request.Cookie(CALLBACK_NONCE)
if err != nil {
api.JSONErrorStatus(context, http.StatusInternalServerError, errors.New("missing id token"))
return
}
if verifiedIDToken.Nonce != nonce.Value {
api.JSONErrorStatus(context, http.StatusBadRequest, errors.New("nonce for verified id token did not match"))
return
}
}
11 changes: 7 additions & 4 deletions handlers/oidc_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ type OIDCAuthHandler struct {
authenticator *auth.Authenticator
}

func NewOIDCAuthHanlder(authenticator *auth.Authenticator) *OIDCAuthHandler {
func NewOIDCAuthHandler(authenticator *auth.Authenticator) *OIDCAuthHandler {
return &OIDCAuthHandler{authenticator: authenticator}
}

func (a *OIDCAuthHandler) OIDCAuthPageHandler(context *gin.Context) {
func (auth *OIDCAuthHandler) OIDCAuthPageHandler(context *gin.Context) {
// context.Header("HX-Redirect", "/dashboard")
// context.String(http.StatusFound, "")
render := utils.NewTempl(context, http.StatusOK, authviews.OIDCLoginIndex())
context.Render(http.StatusOK, render)
}

func (a *OIDCAuthHandler) OIDCLoginHandler(context *gin.Context) {
a.authenticator.RedirectToOIDCLogin(context)
func (auth *OIDCAuthHandler) OIDCLoginHandler(context *gin.Context) {
auth.authenticator.OIDCRedirectToLogin(context)
}

func (auth *OIDCAuthHandler) OIDCCallBackHandler(context *gin.Context) {
}
2 changes: 1 addition & 1 deletion routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Setup(app *gin.Engine) {

func PublicOIDCRoutes(app *gin.RouterGroup) {
auth := auth.SetupOIDCAuthHandler()
authHandler := handlers.NewOIDCAuthHanlder(auth)
authHandler := handlers.NewOIDCAuthHandler(auth)
publicRoute := app.Group("/")
{
publicRoute.GET("/", authHandler.OIDCAuthPageHandler)
Expand Down

0 comments on commit 6038fe6

Please sign in to comment.