diff --git a/controllers/account.go b/controllers/account.go index 9dc223f1..e952dad5 100644 --- a/controllers/account.go +++ b/controllers/account.go @@ -24,8 +24,10 @@ import ( ) const ( - ResponseTypeLogin = "login" - ResponseTypeCode = "code" + ResponseTypeLogin = "login" + ResponseTypeCode = "code" + ResponseTypeToken = "token" + ResponseTypeIdToken = "id_token" ) type RequestForm struct { diff --git a/controllers/auth.go b/controllers/auth.go index e4d797dd..8c6c031f 100644 --- a/controllers/auth.go +++ b/controllers/auth.go @@ -38,6 +38,14 @@ func codeToResponse(code *object.Code) *Response { return &Response{Status: "ok", Msg: "", Data: code.Code} } +func tokenToResponse(token *object.Token) *Response { + if token.AccessToken == "" { + return &Response{Status: "error", Msg: "fail to get accessToken", Data: token.AccessToken} + } + return &Response{Status: "ok", Msg: "", Data: token.AccessToken} + +} + // HandleLoggedIn ... func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *RequestForm) (resp *Response) { userId := user.GetId() @@ -66,6 +74,15 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob // The prompt page needs the user to be signed in c.SetSessionUsername(userId) } + } else if form.Type == ResponseTypeToken || form.Type == ResponseTypeIdToken { //implicit flow + if !object.IsGrantTypeValid(form.Type, application.GrantTypes) { + resp = &Response{Status: "error", Msg: fmt.Sprintf("error: grant_type: %s is not supported in this application", form.Type), Data: ""} + } else { + scope := c.Input().Get("scope") + token, _ := object.GetTokenByUser(application, user, scope, c.Ctx.Request.Host) + resp = tokenToResponse(token) + } + } else { resp = &Response{Status: "error", Msg: fmt.Sprintf("Unknown response type: %s", form.Type)} } diff --git a/object/token.go b/object/token.go index 05d248ca..958d8f55 100644 --- a/object/token.go +++ b/object/token.go @@ -180,8 +180,8 @@ func GetTokenByAccessToken(accessToken string) *Token { } func CheckOAuthLogin(clientId string, responseType string, redirectUri string, scope string, state string) (string, *Application) { - if responseType != "code" { - return "response_type should be \"code\"", nil + if responseType != "code" && responseType != "token" && responseType != "id_token" { + return fmt.Sprintf("error: grant_type: %s is not supported in this application", responseType), nil } application := GetApplicationByClientId(clientId) @@ -274,7 +274,7 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code } //Check if grantType is allowed in the current application - if !isGrantTypeValid(grantType, application.GrantTypes) { + if !IsGrantTypeValid(grantType, application.GrantTypes) { return &TokenWrapper{ AccessToken: fmt.Sprintf("error: grant_type: %s is not supported in this application", grantType), TokenType: "", @@ -418,7 +418,7 @@ func pkceChallenge(verifier string) string { // Check if grantType is allowed in the current application // authorization_code is allowed by default -func isGrantTypeValid(method string, grantTypes []string) bool { +func IsGrantTypeValid(method string, grantTypes []string) bool { if method == "authorization_code" { return true } @@ -527,3 +527,28 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc AddToken(token) return token, nil } + +// Implicit flow +func GetTokenByUser(application *Application, user *User, scope string, host string) (*Token, error) { + accessToken, refreshToken, err := generateJwtToken(application, user, "", scope, host) + if err != nil { + return nil, err + } + token := &Token{ + Owner: application.Owner, + Name: util.GenerateId(), + CreatedTime: util.GetCurrentTime(), + Application: application.Name, + Organization: user.Owner, + User: user.Name, + Code: util.GenerateClientId(), + AccessToken: accessToken, + RefreshToken: refreshToken, + ExpiresIn: application.ExpireInHours * 60, + Scope: scope, + TokenType: "Bearer", + CodeIsUsed: true, + } + AddToken(token) + return token, nil +} diff --git a/web/src/ApplicationEditPage.js b/web/src/ApplicationEditPage.js index 8259dc5c..0bdcd616 100644 --- a/web/src/ApplicationEditPage.js +++ b/web/src/ApplicationEditPage.js @@ -453,6 +453,8 @@ class ApplicationEditPage extends React.Component { {id: "authorization_code", name: "Authorization Code"}, {id: "password", name: "Password"}, {id: "client_credentials", name: "Client Credentials"}, + {id: "token", name: "Token"}, + {id: "id_token",name:"ID Token"}, ].map((item, index)=>) } diff --git a/web/src/auth/AuthCallback.js b/web/src/auth/AuthCallback.js index df146a8e..b80ff81f 100644 --- a/web/src/auth/AuthCallback.js +++ b/web/src/auth/AuthCallback.js @@ -58,6 +58,10 @@ class AuthCallback extends React.Component { if (authServerUrl === realRedirectUrl) { return "login"; } else { + const responseType = innerParams.get("response_type"); + if (responseType !== null) { + return responseType + } return "code"; } } else if (method === "link") { @@ -116,6 +120,9 @@ class AuthCallback extends React.Component { const code = res.data; Setting.goToLink(`${oAuthParams.redirectUri}?code=${code}&state=${oAuthParams.state}`); // Util.showMessage("success", `Authorization code: ${res.data}`); + } else if (responseType === "token" || responseType === "id_token"){ + const token = res.data; + Setting.goToLink(`${oAuthParams.redirectUri}?${responseType}=${token}&state=${oAuthParams.state}&token_type=bearer`); } else if (responseType === "link") { const from = innerParams.get("from"); Setting.goToLinkSoft(this, from); diff --git a/web/src/auth/LoginPage.js b/web/src/auth/LoginPage.js index 53d92dd6..7ce96ce2 100644 --- a/web/src/auth/LoginPage.js +++ b/web/src/auth/LoginPage.js @@ -116,14 +116,18 @@ class LoginPage extends React.Component { onFinish(values) { const application = this.getApplicationObj(); const ths = this; - values["type"] = this.state.type; - values["phonePrefix"] = this.getApplicationObj()?.organizationObj.phonePrefix; const oAuthParams = Util.getOAuthGetParameters(); - + if (oAuthParams !== null && oAuthParams.responseType!= null && oAuthParams.responseType !== "") { + values["type"] = oAuthParams.responseType + }else{ + values["type"] = this.state.type; + } + values["phonePrefix"] = this.getApplicationObj()?.organizationObj.phonePrefix; + AuthBackend.login(values, oAuthParams) .then((res) => { if (res.status === 'ok') { - const responseType = this.state.type; + const responseType = values["type"]; if (responseType === "login") { Util.showMessage("success", `Logged in successfully`); @@ -156,6 +160,9 @@ class LoginPage extends React.Component { } // Util.showMessage("success", `Authorization code: ${res.data}`); + } else if (responseType === "token" || responseType === "id_token") { + const accessToken = res.data; + Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}?state=${oAuthParams.state}&token_type=bearer`); } } else { Util.showMessage("error", `Failed to log in: ${res.msg}`);