diff --git a/server/crypto/common.go b/server/crypto/common.go index 69f674c..35af515 100644 --- a/server/crypto/common.go +++ b/server/crypto/common.go @@ -94,6 +94,7 @@ func EncryptEnvData(data envstore.Store) (string, error) { if err != nil { return "", err } + encryptedConfig, err := EncryptAESEnv(configData) if err != nil { return "", err diff --git a/server/env/persist_env.go b/server/env/persist_env.go index 1459a71..42ba969 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -112,7 +112,7 @@ func PersistEnv() error { for key, value := range storeData.StringEnv { // don't override unexposed envs - if key != constants.EnvKeyEncryptionKey && key != constants.EnvKeyClientID && key != constants.EnvKeyClientSecret && key != constants.EnvKeyJWK { + if key != constants.EnvKeyEncryptionKey { // check only for derivative keys // No need to check for ENCRYPTION_KEY which special key we use for encrypting config data // as we have removed it from json diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index c07bfd2..9dafafe 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -6,10 +6,12 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" + "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" + "github.com/authorizerdev/authorizer/server/utils" "github.com/gin-gonic/gin" "github.com/google/uuid" ) @@ -17,6 +19,7 @@ import ( // AuthorizeHandler is the handler for the /authorize route // required params // ?redirect_uri = redirect url +// ?response_mode = to decide if result should be html or re-direct // state[recommended] = to prevent CSRF attack (for authorizer its compulsory) // code_challenge = to prevent CSRF attack // code_challenge_method = to prevent CSRF attack [only sh256 is supported] @@ -31,56 +34,74 @@ func AuthorizeHandler() gin.HandlerFunc { scopeString := strings.TrimSpace(gc.Query("scope")) clientID := strings.TrimSpace(gc.Query("client_id")) template := "authorize.tmpl" + responseMode := strings.TrimSpace(gc.Query("response_mode")) + + if responseMode == "" { + responseMode = "query" + } + + if responseMode != "query" && responseMode != "web_message" { + gc.JSON(400, gin.H{"error": "invalid response mode"}) + } + + if redirectURI == "" { + redirectURI = "/app" + } + + isQuery := responseMode == "query" + + hostname := utils.GetHost(gc) + loginRedirectState := crypto.EncryptB64(`{"authorizerURL":"` + hostname + `","redirectURL":"` + redirectURI + `"}`) + loginURL := "/app?state=" + loginRedirectState if clientID == "" { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "client_id is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "client_id is required", + }, }, - }, - }) + }) + } return } if clientID != envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID) { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "invalid_client_id", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "invalid_client_id", + }, }, - }, - }) - return - } - - if redirectURI == "" { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "redirect_uri is required", - }, - }, - }) + }) + } return } if state == "" { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "state is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "state is required", + }, }, - }, - }) + }) + } return } @@ -99,76 +120,96 @@ func AuthorizeHandler() gin.HandlerFunc { isResponseTypeToken := responseType == "token" if !isResponseTypeCode && !isResponseTypeToken { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "response_type is invalid", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "response_type is invalid", + }, }, - }, - }) + }) + } return } if isResponseTypeCode { if codeChallenge == "" { - gc.HTML(http.StatusBadRequest, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "code_challenge is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusBadRequest, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "code_challenge is required", + }, }, - }, - }) + }) + } return } } sessionToken, err := cookie.GetSession(gc) if err != nil { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "login_required", + "error_description": "Login is required", + }, }, - }, - }) + }) + } return } // get session from cookie claims, err := token.ValidateBrowserSession(gc, sessionToken) if err != nil { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "login_required", + "error_description": "Login is required", + }, }, - }, - }) + }) + } return } userID := claims.Subject user, err := db.Provider.GetUserByID(userID) if err != nil { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "signup_required", - "error_description": "Sign up required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "signup_required", + "error_description": "Sign up required", + }, }, - }, - }) + }) + } return } @@ -180,16 +221,20 @@ func AuthorizeHandler() gin.HandlerFunc { nonce := uuid.New().String() newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope) if err != nil { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "login_required", + "error_description": "Login is required", + }, }, - }, - }) + }) + } return } @@ -214,16 +259,20 @@ func AuthorizeHandler() gin.HandlerFunc { // rollover the session for security authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope) if err != nil { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "login_required", + "error_description": "Login is required", + }, }, - }, - }) + }) + } return } sessionstore.RemoveState(sessionToken) @@ -256,16 +305,20 @@ func AuthorizeHandler() gin.HandlerFunc { return } - // by default return with error - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", + if isQuery { + gc.Redirect(http.StatusFound, loginURL) + } else { + // by default return with error + gc.HTML(http.StatusOK, template, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "error": "login_required", + "error_description": "Login is required", + }, }, - }, - }) + }) + } } } diff --git a/templates/authorize.tmpl b/templates/authorize.tmpl index cc6c659..ed55daa 100644 --- a/templates/authorize.tmpl +++ b/templates/authorize.tmpl @@ -8,7 +8,6 @@ (function (window, document) { var targetOrigin = {{.target_origin}}; var authorizationResponse = {{.authorization_response}}; - console.log({targetOrigin}) window.parent.postMessage(authorizationResponse, targetOrigin); })(this, this.document);