fix: oauth login

This commit is contained in:
Lakhan Samani 2022-03-07 08:31:39 +05:30
parent 07552bc0b1
commit e61dc2f08a
5 changed files with 83 additions and 31 deletions

View File

@ -4,8 +4,10 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/sessionstore"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -27,12 +29,38 @@ func AuthorizeHandler() gin.HandlerFunc {
state := strings.TrimSpace(gc.Query("state")) state := strings.TrimSpace(gc.Query("state"))
codeChallenge := strings.TrimSpace(gc.Query("code_challenge")) codeChallenge := strings.TrimSpace(gc.Query("code_challenge"))
scopeString := strings.TrimSpace(gc.Query("scope")) scopeString := strings.TrimSpace(gc.Query("scope"))
scope := []string{} clientID := strings.TrimSpace(gc.Query("client_id"))
template := "authorize.tmpl" template := "authorize.tmpl"
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",
},
},
})
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",
},
},
})
return
}
if redirectURI == "" { if redirectURI == "" {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -45,7 +73,7 @@ func AuthorizeHandler() gin.HandlerFunc {
if state == "" { if state == "" {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -60,8 +88,11 @@ func AuthorizeHandler() gin.HandlerFunc {
responseType = "token" responseType = "token"
} }
var scope []string
if scopeString == "" { if scopeString == "" {
scope = []string{"openid", "profile", "email"} scope = []string{"openid", "profile", "email"}
} else {
scope = strings.Split(scopeString, " ")
} }
isResponseTypeCode := responseType == "code" isResponseTypeCode := responseType == "code"
@ -69,7 +100,7 @@ func AuthorizeHandler() gin.HandlerFunc {
if !isResponseTypeCode && !isResponseTypeToken { if !isResponseTypeCode && !isResponseTypeToken {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -83,7 +114,7 @@ func AuthorizeHandler() gin.HandlerFunc {
if isResponseTypeCode { if isResponseTypeCode {
if codeChallenge == "" { if codeChallenge == "" {
gc.HTML(http.StatusBadRequest, template, gin.H{ gc.HTML(http.StatusBadRequest, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -98,7 +129,7 @@ func AuthorizeHandler() gin.HandlerFunc {
sessionToken, err := cookie.GetSession(gc) sessionToken, err := cookie.GetSession(gc)
if err != nil { if err != nil {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -114,7 +145,7 @@ func AuthorizeHandler() gin.HandlerFunc {
claims, err := token.ValidateBrowserSession(gc, sessionToken) claims, err := token.ValidateBrowserSession(gc, sessionToken)
if err != nil { if err != nil {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -129,7 +160,7 @@ func AuthorizeHandler() gin.HandlerFunc {
user, err := db.Provider.GetUserByID(userID) user, err := db.Provider.GetUserByID(userID)
if err != nil { if err != nil {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -150,7 +181,7 @@ func AuthorizeHandler() gin.HandlerFunc {
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope) newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope)
if err != nil { if err != nil {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -168,9 +199,12 @@ func AuthorizeHandler() gin.HandlerFunc {
sessionstore.SetState(codeChallenge, code+"@"+newSessionToken) sessionstore.SetState(codeChallenge, code+"@"+newSessionToken)
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI, "target_origin": redirectURI,
"authorization_response": map[string]string{ "authorization_response": map[string]interface{}{
"code": code, "type": "authorization_response",
"state": state, "response": map[string]string{
"code": code,
"state": state,
},
}, },
}) })
return return
@ -181,7 +215,7 @@ func AuthorizeHandler() gin.HandlerFunc {
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope) authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope)
if err != nil { if err != nil {
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{
@ -213,15 +247,18 @@ func AuthorizeHandler() gin.HandlerFunc {
} }
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": redirectURI, "target_origin": redirectURI,
"authorization_response": res, "authorization_response": map[string]interface{}{
"type": "authorization_response",
"response": res,
},
}) })
return return
} }
// by default return with error // by default return with error
gc.HTML(http.StatusOK, template, gin.H{ gc.HTML(http.StatusOK, template, gin.H{
"target_origin": nil, "target_origin": redirectURI,
"authorization_response": map[string]interface{}{ "authorization_response": map[string]interface{}{
"type": "authorization_response", "type": "authorization_response",
"response": map[string]string{ "response": map[string]string{

View File

@ -21,6 +21,7 @@ import (
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@ -146,10 +147,14 @@ func OAuthCallbackHandler() gin.HandlerFunc {
// TODO use query param // TODO use query param
scope := []string{"openid", "email", "profile"} scope := []string{"openid", "email", "profile"}
authToken, _ := token.CreateAuthToken(c, user, inputRoles, scope) nonce := uuid.New().String()
_, newSessionToken, err := token.CreateSessionToken(user, nonce, inputRoles, scope)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
}
sessionstore.SetState(authToken.FingerPrint, user.ID) sessionstore.SetState(newSessionToken, nonce+"@"+user.ID)
cookie.SetSession(c, authToken.FingerPrintHash) cookie.SetSession(c, newSessionToken)
go utils.SaveSessionInDB(c, user.ID) go utils.SaveSessionInDB(c, user.ID)
c.Redirect(http.StatusTemporaryRedirect, redirectURL) c.Redirect(http.StatusTemporaryRedirect, redirectURL)
} }

View File

@ -6,8 +6,10 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/sessionstore"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -26,7 +28,23 @@ func TokenHandler() gin.HandlerFunc {
codeVerifier := strings.TrimSpace(reqBody["code_verifier"]) codeVerifier := strings.TrimSpace(reqBody["code_verifier"])
code := strings.TrimSpace(reqBody["code"]) code := strings.TrimSpace(reqBody["code"])
redirectURI := strings.TrimSpace(reqBody["redirect_uri"]) clientID := strings.TrimSpace(reqBody["client_id"])
if clientID == "" {
gc.JSON(http.StatusBadRequest, gin.H{
"error": "client_id_required",
"error_description": "The client id is required",
})
return
}
if clientID != envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID) {
gc.JSON(http.StatusBadRequest, gin.H{
"error": "invalid_client_id",
"error_description": "The client id is invalid",
})
return
}
if codeVerifier == "" { if codeVerifier == "" {
gc.JSON(http.StatusBadRequest, gin.H{ gc.JSON(http.StatusBadRequest, gin.H{
@ -44,14 +62,6 @@ func TokenHandler() gin.HandlerFunc {
return return
} }
if redirectURI == "" {
gc.JSON(http.StatusBadRequest, gin.H{
"error": "invalid_redirect_uri",
"error_description": "The redirect URI is required",
})
return
}
hash := sha256.New() hash := sha256.New()
hash.Write([]byte(codeVerifier)) hash.Write([]byte(codeVerifier))
encryptedCode := strings.ReplaceAll(base64.URLEncoding.EncodeToString(hash.Sum(nil)), "+", "-") encryptedCode := strings.ReplaceAll(base64.URLEncoding.EncodeToString(hash.Sum(nil)), "+", "-")

View File

@ -26,7 +26,7 @@ func InitRouter() *gin.Engine {
router.GET("/authorize", handlers.AuthorizeHandler()) router.GET("/authorize", handlers.AuthorizeHandler())
router.GET("/userinfo", handlers.UserInfoHandler()) router.GET("/userinfo", handlers.UserInfoHandler())
router.GET("/logout", handlers.LogoutHandler()) router.GET("/logout", handlers.LogoutHandler())
router.POST("/token", handlers.TokenHandler()) router.POST("/oauth/token", handlers.TokenHandler())
router.LoadHTMLGlob("templates/*") router.LoadHTMLGlob("templates/*")
// login page app related routes. // login page app related routes.

View File

@ -8,8 +8,8 @@
(function (window, document) { (function (window, document) {
var targetOrigin = {{.target_origin}}; var targetOrigin = {{.target_origin}};
var authorizationResponse = {{.authorization_response}}; var authorizationResponse = {{.authorization_response}};
var mainWin = window.parent; console.log({targetOrigin})
mainWin.postMessage(authorizationResponse, targetOrigin); window.parent.postMessage(authorizationResponse, targetOrigin);
})(this, this.document); })(this, this.document);
</script> </script>
</body> </body>