From beb55afd091461a03c6cd2b29fd2f448733fe33c Mon Sep 17 00:00:00 2001 From: Darshan Kumar Date: Sun, 27 Nov 2022 23:33:19 +0530 Subject: [PATCH 1/5] project init --- .gitignore | 3 +++ config/kratos_config.yaml | 25 +++++++++++++++++++++++++ config/oidc.google.jsonnet | 11 +++++++++++ 3 files changed, 39 insertions(+) create mode 100644 config/oidc.google.jsonnet diff --git a/.gitignore b/.gitignore index a15ed80..0e6d89c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ config.yaml # Exclude air temp directory target/ + +#Exclude values.yaml +/config/values.yaml \ No newline at end of file diff --git a/config/kratos_config.yaml b/config/kratos_config.yaml index ead11c9..8b20109 100644 --- a/config/kratos_config.yaml +++ b/config/kratos_config.yaml @@ -1,5 +1,30 @@ selfservice: strategies: + oidc: + config: + providers: + - id: google # this is `` in the Authorization callback URL. DO NOT CHANGE IT ONCE SET! + provider: google + client_id: {{google.client_id}} # Replace this with the OAuth2 Client ID + client_secret: {{google.client_secret}} # Replace this with the OAuth2 Client secret + mapper_url: file:///etc/config/kratos/oidc.google.jsonnet + # Alternatively, use an URL: + # mapper_url: https://storage.googleapis.com/abc-cde-prd/9cac9717f007808bf17f22ce7f4295c739604b183f05ac4afb4 + scope: + - email + - profile + # other supported scopes can be found in Google OAuth 2.0 dev docs + requested_claims: + id_token: + email: + essential: true + email_verified: + essential: true + given_name: + essential: true + family_name: null + hd: null # If you want the Google Workspace domain + enabled: true password: enabled: true diff --git a/config/oidc.google.jsonnet b/config/oidc.google.jsonnet new file mode 100644 index 0000000..b03ff9f --- /dev/null +++ b/config/oidc.google.jsonnet @@ -0,0 +1,11 @@ +local claims = { + email_verified: true, +} + std.extVar('claims'); + +{ + identity: { + traits: { + [if 'email' in claims && claims.email_verified then 'email' else null]: claims.email, + }, + }, +} \ No newline at end of file From 11cd2690d0610bad201cd155510aff2ffe906807 Mon Sep 17 00:00:00 2001 From: Darshan Kumar Date: Wed, 28 Dec 2022 02:38:58 +0530 Subject: [PATCH 2/5] add OIDC endpoints+OIDCReg Wrapper func and OIDCHandle func --- api/main.go | 3 ++- api/oidc.go | 40 ++++++++++++++++++++++++++++++++ pkg/wrapper/kratos/oidc/oidc.go | 28 ++++++++++++++++++++++ pkg/wrapper/kratos/oidc/types.go | 6 +++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 api/oidc.go create mode 100644 pkg/wrapper/kratos/oidc/oidc.go create mode 100644 pkg/wrapper/kratos/oidc/types.go diff --git a/api/main.go b/api/main.go index 3eb2c0e..51c392d 100644 --- a/api/main.go +++ b/api/main.go @@ -33,7 +33,8 @@ func Start() { r.GET("/recovery", HandleGetRecoveryFlow) r.POST("/recovery", HandlePostRecoveryFlow) - + r.POST("/login/oidc/:provider", HandleOIDCLogin) + r.POST("/register/oidc/:provider", HandleOIDCRegister) r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") } diff --git a/api/oidc.go b/api/oidc.go new file mode 100644 index 0000000..87724a7 --- /dev/null +++ b/api/oidc.go @@ -0,0 +1,40 @@ +package api + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/sdslabs/nymeria/log" + "github.com/sdslabs/nymeria/pkg/wrapper/kratos/login" + "github.com/sdslabs/nymeria/pkg/wrapper/kratos/registration" +) + +func HandleOIDCLogin(c *gin.Context) { + log.Logger.Debug("Get Google Login") + cookie, flowID, csrf_token, err := login.InitializeLoginFlowWrapper() + + if err != nil { + log.ErrorLogger("Intialize OIDC Login Failed", err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "internal server error", + }) + return + } + c.SetCookie("googlelogin_flow", cookie, 3600, "/", "localhost", false, true) + +} + +func HandleOIDCRegister(c *gin.Context) { + cookie, flowID, csrf_token, err := registration.InitializeRegistrationFlowWrapper() + + if err != nil { + log.ErrorLogger("Kratos get OIDC registration flow failed", err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "internal server error", + }) + return + } + + c.SetCookie("registration_flow", cookie, 3600, "/", "localhost", false, true) + +} \ No newline at end of file diff --git a/pkg/wrapper/kratos/oidc/oidc.go b/pkg/wrapper/kratos/oidc/oidc.go new file mode 100644 index 0000000..13d198d --- /dev/null +++ b/pkg/wrapper/kratos/oidc/oidc.go @@ -0,0 +1,28 @@ +package oidc + +import ( + "context" + "fmt" + "os" + + client "github.com/ory/kratos-client-go" + "github.com/sdslabs/nymeria/config" +) + +func SubmitOIDCRegistrationFlowWrapper(provider string, cookie string, flowID string, csrfToken string) (string, error) { + submitOIDCRegistrationFlowBody := client.SubmitSelfServiceRegistrationFlowBody{ + SubmitSelfServiceRegistrationFlowWithOidcMethodBody: client.NewSubmitSelfServiceRegistrationFlowWithOidcMethodBody("oidc", provider), + } + + submitOIDCRegistrationFlowBody.SubmitSelfServiceRegistrationFlowWithOidcMethodBody.SetCsrfToken(csrfToken) + + apiClient := client.NewAPIClient(config.KratosClientConfig) + _, r, err := apiClient.V0alpha2Api.SubmitSelfServiceRegistrationFlow(context.Background()).Flow(flowID).SubmitSelfServiceRegistrationFlowBody(submitOIDCRegistrationFlowBody).Cookie(cookie).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.SubmitSelfServiceRegistrationFlow``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + + responseCookies := r.Header["Set-Cookie"] + return responseCookies[1], nil +} \ No newline at end of file diff --git a/pkg/wrapper/kratos/oidc/types.go b/pkg/wrapper/kratos/oidc/types.go new file mode 100644 index 0000000..ed15a2f --- /dev/null +++ b/pkg/wrapper/kratos/oidc/types.go @@ -0,0 +1,6 @@ +package oidc + +type SubmitOIDCLoginAPIBody struct { + FlowID string `json:"flowID"` + CsrfToken string `json:"csrf_token"` +} From 2d2f7be8de2eceb1121731fe05b0d2ab64fbf0a7 Mon Sep 17 00:00:00 2001 From: Darshan Kumar Date: Wed, 28 Dec 2022 03:22:49 +0530 Subject: [PATCH 3/5] complete OIDC Registration Flow --- api/oidc.go | 36 +++++++++++++++++++++++++++++++-- pkg/wrapper/kratos/oidc/oidc.go | 2 +- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/api/oidc.go b/api/oidc.go index 87724a7..41cf29e 100644 --- a/api/oidc.go +++ b/api/oidc.go @@ -7,10 +7,11 @@ import ( "github.com/sdslabs/nymeria/log" "github.com/sdslabs/nymeria/pkg/wrapper/kratos/login" "github.com/sdslabs/nymeria/pkg/wrapper/kratos/registration" + "github.com/sdslabs/nymeria/pkg/wrapper/kratos/oidc" ) func HandleOIDCLogin(c *gin.Context) { - log.Logger.Debug("Get Google Login") + log.Logger.Debug("Get OIDC Login") cookie, flowID, csrf_token, err := login.InitializeLoginFlowWrapper() if err != nil { @@ -25,6 +26,14 @@ func HandleOIDCLogin(c *gin.Context) { } func HandleOIDCRegister(c *gin.Context) { + log.Logger.Debug("Get OIDC Registration") + provider := c.Param("provider") + if provider == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "provider not found", + }) + return + } cookie, flowID, csrf_token, err := registration.InitializeRegistrationFlowWrapper() if err != nil { @@ -35,6 +44,29 @@ func HandleOIDCRegister(c *gin.Context) { return } - c.SetCookie("registration_flow", cookie, 3600, "/", "localhost", false, true) + c.SetCookie("OIDC_registration_flow", cookie, 3600, "/", "localhost", false, true) + //In case we need to separate the flows so setting and getting cookies simultaneously + afterCookie, err := c.Cookie("OIDC_registration_flow") + + if err != nil { + log.ErrorLogger("Cookie not found", err) + c.JSON(http.StatusBadRequest, gin.H{ + "error": "csrf cookie not found", + }) + return + } + session, err := oidc.SubmitOIDCRegistrationFlowWrapper(provider, afterCookie, flowID, csrf_token) + + if err != nil { + log.ErrorLogger("Kratos post registration flow failed", err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "internal server error", + }) + return + } + c.SetCookie("sdslabs_session", session, 3600, "/", "localhost", false, true) + c.JSON(http.StatusOK, gin.H{ + "status": "created", + }) } \ No newline at end of file diff --git a/pkg/wrapper/kratos/oidc/oidc.go b/pkg/wrapper/kratos/oidc/oidc.go index 13d198d..eb606f7 100644 --- a/pkg/wrapper/kratos/oidc/oidc.go +++ b/pkg/wrapper/kratos/oidc/oidc.go @@ -25,4 +25,4 @@ func SubmitOIDCRegistrationFlowWrapper(provider string, cookie string, flowID st responseCookies := r.Header["Set-Cookie"] return responseCookies[1], nil -} \ No newline at end of file +} From 61bb8b9f51592cc3a6697b22898b3aa718e6b448 Mon Sep 17 00:00:00 2001 From: Darshan Kumar Date: Wed, 28 Dec 2022 04:12:19 +0530 Subject: [PATCH 4/5] complete OIDC Login flow --- api/oidc.go | 40 ++++++++++++++++++++++++++++---- pkg/wrapper/kratos/oidc/oidc.go | 18 +++++++++++++- pkg/wrapper/kratos/oidc/types.go | 6 ----- 3 files changed, 53 insertions(+), 11 deletions(-) delete mode 100644 pkg/wrapper/kratos/oidc/types.go diff --git a/api/oidc.go b/api/oidc.go index 41cf29e..85c82df 100644 --- a/api/oidc.go +++ b/api/oidc.go @@ -6,12 +6,19 @@ import ( "github.com/gin-gonic/gin" "github.com/sdslabs/nymeria/log" "github.com/sdslabs/nymeria/pkg/wrapper/kratos/login" - "github.com/sdslabs/nymeria/pkg/wrapper/kratos/registration" "github.com/sdslabs/nymeria/pkg/wrapper/kratos/oidc" + "github.com/sdslabs/nymeria/pkg/wrapper/kratos/registration" ) func HandleOIDCLogin(c *gin.Context) { log.Logger.Debug("Get OIDC Login") + provider := c.Param("provider") + if provider == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "provider not found", + }) + return + } cookie, flowID, csrf_token, err := login.InitializeLoginFlowWrapper() if err != nil { @@ -21,7 +28,32 @@ func HandleOIDCLogin(c *gin.Context) { }) return } - c.SetCookie("googlelogin_flow", cookie, 3600, "/", "localhost", false, true) + c.SetCookie("OIDC_login_flow", cookie, 3600, "/", "localhost", false, true) + //In case we need to separate the flows so setting and getting cookies simultaneously + afterCookie, err := c.Cookie("OIDC_login_flow") + + if err != nil { + log.ErrorLogger("Cookie not found", err) + c.JSON(http.StatusBadRequest, gin.H{ + "error": "csrf cookie not found", + }) + return + } + + session, err := oidc.SubmitOIDCLoginFlowWrapper(provider, afterCookie, flowID, csrf_token) + + if err != nil { + log.ErrorLogger("Kratos post OIDC login flow failed", err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "internal server error", + }) + return + } + + c.SetCookie("sdslabs_session", session, 3600, "/", "localhost", false, true) + c.JSON(http.StatusOK, gin.H{ + "status": "user logged in via OIDC", + }) } @@ -58,7 +90,7 @@ func HandleOIDCRegister(c *gin.Context) { session, err := oidc.SubmitOIDCRegistrationFlowWrapper(provider, afterCookie, flowID, csrf_token) if err != nil { - log.ErrorLogger("Kratos post registration flow failed", err) + log.ErrorLogger("Kratos OIDC post registration flow failed", err) c.JSON(http.StatusInternalServerError, gin.H{ "error": "internal server error", }) @@ -66,7 +98,7 @@ func HandleOIDCRegister(c *gin.Context) { } c.SetCookie("sdslabs_session", session, 3600, "/", "localhost", false, true) c.JSON(http.StatusOK, gin.H{ - "status": "created", + "status": "created via OIDC", }) } \ No newline at end of file diff --git a/pkg/wrapper/kratos/oidc/oidc.go b/pkg/wrapper/kratos/oidc/oidc.go index eb606f7..bf79d92 100644 --- a/pkg/wrapper/kratos/oidc/oidc.go +++ b/pkg/wrapper/kratos/oidc/oidc.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - client "github.com/ory/kratos-client-go" + client "github.com/ory/client-go" "github.com/sdslabs/nymeria/config" ) @@ -26,3 +26,19 @@ func SubmitOIDCRegistrationFlowWrapper(provider string, cookie string, flowID st responseCookies := r.Header["Set-Cookie"] return responseCookies[1], nil } + +func SubmitOIDCLoginFlowWrapper(provider string, cookie string, flowID string, csrfToken string) (string, error) { + submitOIDCLoginFlowBody := client.SubmitSelfServiceLoginFlowBody{SubmitSelfServiceLoginFlowWithOidcMethodBody: client.NewSubmitSelfServiceLoginFlowWithOidcMethodBody("oidc", provider)} // SubmitSelfServiceLoginFlowBody | + + submitOIDCLoginFlowBody.SubmitSelfServiceLoginFlowWithOidcMethodBody.SetCsrfToken(csrfToken) + + apiClient := client.NewAPIClient(config.KratosClientConfig) + _, r, err := apiClient.V0alpha2Api.SubmitSelfServiceLoginFlow(context.Background()).Flow(flowID).SubmitSelfServiceLoginFlowBody(submitOIDCLoginFlowBody).XSessionToken("").Cookie(cookie).Execute() + if err != nil { + return "", err + } + + responseCookies := r.Header["Set-Cookie"] + + return responseCookies[1], nil +} diff --git a/pkg/wrapper/kratos/oidc/types.go b/pkg/wrapper/kratos/oidc/types.go deleted file mode 100644 index ed15a2f..0000000 --- a/pkg/wrapper/kratos/oidc/types.go +++ /dev/null @@ -1,6 +0,0 @@ -package oidc - -type SubmitOIDCLoginAPIBody struct { - FlowID string `json:"flowID"` - CsrfToken string `json:"csrf_token"` -} From 6de9c582deb04c44677e76e18d9db924db6505c9 Mon Sep 17 00:00:00 2001 From: Darshan Kumar Date: Wed, 28 Dec 2022 04:17:29 +0530 Subject: [PATCH 5/5] small fix --- pkg/controller/admin/identity.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/controller/admin/identity.go b/pkg/controller/admin/identity.go index 63e1980..8a650a2 100644 --- a/pkg/controller/admin/identity.go +++ b/pkg/controller/admin/identity.go @@ -7,7 +7,6 @@ import ( "net/http" "os" "strconv" - "strings" "github.com/gin-gonic/gin" client "github.com/ory/client-go"