Compare commits

..

9 Commits

Author SHA1 Message Date
Товарищ программист
ca0fa5fc40 fix: fix missing parameters when signup (#533) 2022-03-05 16:47:08 +08:00
Nekotoxin
cfbce79e32 fix: add ie support (ie >= 9) (#538)
* fix: add ie support (ie > 9)

* fix: add support for IE11

* fix: small fix

* fix: fix
2022-03-05 16:32:37 +08:00
Yang Luo
efc07f0919 Improve translation. 2022-03-05 00:53:59 +08:00
fuh
a783315fa2 fix: Returns a valid userId when form.Username is empty (#523)
* fix: Returns a valid userId when form.Username is empty

* fix: format code
2022-03-04 23:39:12 +08:00
Steve0x2a
1d0af9cf7b fix: client_credentials' token miss some claims (#536)
Signed-off-by: Steve0x2a <stevesough@gmail.com>
2022-03-04 22:57:31 +08:00
Nekotoxin
4d48517be9 fix: fix the No.0 bug(for all sign up methods) (#535) 2022-03-04 13:06:21 +08:00
Leon
178cf7945d feat: improve token introspection endpoint (#534)
* feat: add introspection endpoint to oidc discovery endpoint

* fix: let introspect endpoint handle formData as spec define.

Signed-off-by: Leon <leondevlifelog@gmail.com>
2022-03-04 08:54:33 +08:00
Leon
ab5af979c8 feat: add Oauth 2.0 Token Introspection(rfc7662) endpoint support (#532)
Signed-off-by: Leon <leondevlifelog@gmail.com>
2022-03-03 17:48:47 +08:00
Gucheng Wang
e31aaf5657 Rename httpProxy. 2022-03-03 08:59:38 +08:00
24 changed files with 165 additions and 25 deletions

View File

@@ -12,7 +12,7 @@ redisEndpoint =
defaultStorageProvider =
isCloudIntranet = false
authState = "casdoor"
httpProxy = "127.0.0.1:10808"
sock5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10
initScore = 2000
logPostOnly = true

View File

@@ -130,8 +130,6 @@ func (c *ApiController) Signup() {
}
}
userId := fmt.Sprintf("%s/%s", form.Organization, form.Username)
id := util.GenerateId()
if application.GetSignupItemRule("ID") == "Incremental" {
lastUser := object.GetLastUser(form.Organization)
@@ -149,8 +147,6 @@ func (c *ApiController) Signup() {
username = id
}
userCount := object.GetUserCount(form.Organization, "", "") + 1
user := &object.User{
Owner: form.Organization,
Name: username,
@@ -173,7 +169,6 @@ func (c *ApiController) Signup() {
IsDeleted: false,
SignupApplication: application.Name,
Properties: map[string]string{},
Ranking: userCount + 1,
Karma: 0,
}
@@ -206,6 +201,7 @@ func (c *ApiController) Signup() {
record.User = user.Name
go object.AddRecord(record)
userId := fmt.Sprintf("%s/%s", user.Owner, user.Name)
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
c.ResponseOk(userId)

View File

@@ -229,3 +229,65 @@ func (c *ApiController) TokenLogout() {
c.Data["json"] = wrapActionResponse(flag)
c.ServeJSON()
}
// IntrospectToken
// @Title IntrospectToken
// @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a
// parameter representing an OAuth 2.0 token and returns a JSON document
// representing the meta information surrounding the
// token, including whether this token is currently active.
// This endpoint only support Basic Authorization.
// @Param token formData string true "access_token's value or refresh_token's value"
// @Param token_type_hint formData string true "the token type access_token or refresh_token"
// @Success 200 {object} object.IntrospectionResponse The Response object
// @router /login/oauth/introspect [post]
func (c *ApiController) IntrospectToken() {
tokenValue := c.Input().Get("token")
clientId, clientSecret, ok := c.Ctx.Request.BasicAuth()
if !ok {
util.LogWarning(c.Ctx, "Basic Authorization parses failed")
c.Data["json"] = Response{Status: "error", Msg: "Unauthorized operation"}
c.ServeJSON()
return
}
application := object.GetApplicationByClientId(clientId)
if application == nil || application.ClientSecret != clientSecret {
util.LogWarning(c.Ctx, "Basic Authorization failed")
c.Data["json"] = Response{Status: "error", Msg: "Unauthorized operation"}
c.ServeJSON()
return
}
token := object.GetTokenByTokenAndApplication(tokenValue, application.Name)
if token == nil {
util.LogWarning(c.Ctx, "application: %s can not find token", application.Name)
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
if err != nil || jwtToken.Valid() != nil {
// and token revoked case. but we not implement
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
// refs: https://tools.ietf.org/html/rfc7009
util.LogWarning(c.Ctx, "token invalid")
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
c.Data["json"] = &object.IntrospectionResponse{
Active: true,
Scope: jwtToken.Scope,
ClientId: clientId,
Username: token.User,
TokenType: token.TokenType,
Exp: jwtToken.ExpiresAt.Unix(),
Iat: jwtToken.IssuedAt.Unix(),
Nbf: jwtToken.NotBefore.Unix(),
Sub: jwtToken.Subject,
Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.Id,
}
c.ServeJSON()
}

View File

@@ -16,7 +16,7 @@ data:
defaultStorageProvider =
isCloudIntranet = false
authState = "casdoor"
httpProxy = "127.0.0.1:10808"
sock5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10
initScore = 2000
logPostOnly = true

View File

@@ -30,6 +30,7 @@ type OidcDiscovery struct {
TokenEndpoint string `json:"token_endpoint"`
UserinfoEndpoint string `json:"userinfo_endpoint"`
JwksUri string `json:"jwks_uri"`
IntrospectionEndpoint string `json:"introspection_endpoint"`
ResponseTypesSupported []string `json:"response_types_supported"`
ResponseModesSupported []string `json:"response_modes_supported"`
GrantTypesSupported []string `json:"grant_types_supported"`
@@ -74,6 +75,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
TokenEndpoint: fmt.Sprintf("%s/api/login/oauth/access_token", originBackend),
UserinfoEndpoint: fmt.Sprintf("%s/api/userinfo", originBackend),
JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend),
IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend),
ResponseTypesSupported: []string{"id_token"},
ResponseModesSupported: []string{"login", "code", "link"},
GrantTypesSupported: []string{"password", "authorization_code"},

View File

@@ -60,6 +60,21 @@ type TokenWrapper struct {
Scope string `json:"scope"`
}
type IntrospectionResponse struct {
Active bool `json:"active"`
Scope string `json:"scope,omitempty"`
ClientId string `json:"client_id,omitempty"`
Username string `json:"username,omitempty"`
TokenType string `json:"token_type,omitempty"`
Exp int64 `json:"exp,omitempty"`
Iat int64 `json:"iat,omitempty"`
Nbf int64 `json:"nbf,omitempty"`
Sub string `json:"sub,omitempty"`
Aud []string `json:"aud,omitempty"`
Iss string `json:"iss,omitempty"`
Jti string `json:"jti,omitempty"`
}
func GetTokenCount(owner, field, value string) int {
session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&Token{})
@@ -198,6 +213,15 @@ func GetTokenByAccessToken(accessToken string) *Token {
return &token
}
func GetTokenByTokenAndApplication(token string, application string) *Token {
tokenResult := Token{}
existed, err := adapter.Engine.Where("(refresh_token = ? or access_token = ? ) and application = ?", token, token, application).Get(&tokenResult)
if err != nil || !existed {
return nil
}
return &tokenResult
}
func CheckOAuthLogin(clientId string, responseType string, redirectUri string, scope string, state string) (string, *Application) {
if responseType != "code" && responseType != "token" && responseType != "id_token" {
return fmt.Sprintf("error: grant_type: %s is not supported in this application", responseType), nil
@@ -532,7 +556,9 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
return nil, errors.New("error: invalid client_secret")
}
nullUser := &User{
Name: fmt.Sprintf("app/%s", application.Name),
Owner: application.Owner,
Id: application.GetId(),
Name: fmt.Sprintf("app/%s", application.Name),
}
accessToken, _, err := generateJwtToken(application, nullUser, "", scope, host)
if err != nil {

View File

@@ -147,3 +147,7 @@ func ParseJwtToken(token string, cert *Cert) (*Claims, error) {
return nil, err
}
func ParseJwtTokenByApplication(token string, application *Application) (*Claims, error) {
return ParseJwtToken(token, getCertByApplication(application))
}

View File

@@ -352,6 +352,8 @@ func AddUser(user *User) bool {
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
user.Ranking = GetUserCount(user.Owner, "", "") + 1
affected, err := adapter.Engine.Insert(user)
if err != nil {
panic(err)

View File

@@ -54,17 +54,17 @@ func isAddressOpen(address string) bool {
}
func getProxyHttpClient() *http.Client {
httpProxy := beego.AppConfig.String("httpProxy")
if httpProxy == "" {
sock5Proxy := beego.AppConfig.String("sock5Proxy")
if sock5Proxy == "" {
return &http.Client{}
}
if !isAddressOpen(httpProxy) {
if !isAddressOpen(sock5Proxy) {
return &http.Client{}
}
// https://stackoverflow.com/questions/33585587/creating-a-go-socks5-client
dialer, err := proxy.SOCKS5("tcp", httpProxy, nil, proxy.Direct)
dialer, err := proxy.SOCKS5("tcp", sock5Proxy, nil, proxy.Direct)
if err != nil {
panic(err)
}

View File

@@ -127,6 +127,7 @@ func initAPI() {
beego.Router("/api/login/oauth/code", &controllers.ApiController{}, "POST:GetOAuthCode")
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
beego.Router("/api/login/oauth/logout", &controllers.ApiController{}, "GET:TokenLogout")
beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords")

View File

@@ -29,7 +29,9 @@
"react-i18next": "^11.8.7",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"react-social-login-buttons": "^3.4.0"
"react-social-login-buttons": "^3.4.0",
"react-app-polyfill": "^3.0.0",
"core-js": "^3.21.1"
},
"scripts": {
"start": "cross-env PORT=7001 craco start",
@@ -46,12 +48,14 @@
"production": [
">0.2%",
"not dead",
"not op_mini all"
"not op_mini all",
"ie > 8"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
"last 1 safari version",
"ie > 8"
]
},
"devDependencies": {

View File

@@ -166,7 +166,7 @@ class ApplicationEditPage extends React.Component {
</Row>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel("general:Logo", i18next.t("general:Logo - Tooltip"))} :
{Setting.getLabel(i18next.t("general:Logo"), i18next.t("general:Logo - Tooltip"))} :
</Col>
<Col span={22} style={(Setting.isMobile()) ? {maxWidth:'100%'} :{}}>
<Row style={{marginTop: '20px'}} >

View File

@@ -484,6 +484,7 @@ class LoginPage extends React.Component {
<span style={{float: "right"}}>
{i18next.t("login:No account?")}&nbsp;
<a onClick={() => {
sessionStorage.setItem("loginURL", window.location.href)
Setting.goToSignup(this, application);
}}>
{i18next.t("login:sign up now")}

View File

@@ -65,7 +65,12 @@ class ResultPage extends React.Component {
subTitle={i18next.t("signup:Please click the below button to sign in")}
extra={[
<Button type="primary" key="login" onClick={() => {
Setting.goToLogin(this, application);
let linkInStorage = sessionStorage.getItem("loginURL")
if (linkInStorage != "") {
Setting.goToLink(linkInStorage)
} else {
Setting.goToLogin(this, application)
}
}}>
{i18next.t("login:Sign In")}
</Button>

View File

@@ -557,7 +557,12 @@ class SignupPage extends React.Component {
</Button>
&nbsp;&nbsp;{i18next.t("signup:Have account?")}&nbsp;
<a onClick={() => {
Setting.goToLogin(this, application);
let linkInStorage = sessionStorage.getItem("loginURL")
if(linkInStorage != ""){
Setting.goToLink(linkInStorage)
}else{
Setting.goToLogin(this, application)
}
}}>
{i18next.t("signup:sign in now")}
</a>

View File

@@ -12,18 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import 'core-js/es';
import 'react-app-polyfill/ie9';
import 'react-app-polyfill/stable';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter } from 'react-router-dom';
import {BrowserRouter} from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
<BrowserRouter>
<App/>
</BrowserRouter>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change

View File

@@ -126,6 +126,7 @@
"LDAPs": "LDAPs",
"LDAPs - Tooltip": "LDAPs - Tooltip",
"Last name": "Last name",
"Logo": "Logo",
"Logo - Tooltip": "App's image tag",
"Master password": "Master-Passwort",
"Master password - Tooltip": "Masterpasswort - Tooltip",

View File

@@ -126,6 +126,7 @@
"LDAPs": "LDAPs",
"LDAPs - Tooltip": "LDAPs - Tooltip",
"Last name": "Last name",
"Logo": "Logo",
"Logo - Tooltip": "Logo - Tooltip",
"Master password": "Master password",
"Master password - Tooltip": "Master password - Tooltip",

View File

@@ -126,6 +126,7 @@
"LDAPs": "LDAPs",
"LDAPs - Tooltip": "LDAPs - Infobulle",
"Last name": "Last name",
"Logo": "Logo",
"Logo - Tooltip": "App's image tag",
"Master password": "Mot de passe maître",
"Master password - Tooltip": "Mot de passe maître - Infobulle",

View File

@@ -126,6 +126,7 @@
"LDAPs": "LDAP",
"LDAPs - Tooltip": "LDAP - ツールチップ",
"Last name": "Last name",
"Logo": "Logo",
"Logo - Tooltip": "App's image tag",
"Master password": "マスターパスワード",
"Master password - Tooltip": "マスターパスワード - ツールチップ",

View File

@@ -126,6 +126,7 @@
"LDAPs": "LDAPs",
"LDAPs - Tooltip": "LDAPs - Tooltip",
"Last name": "Last name",
"Logo": "Logo",
"Logo - Tooltip": "App's image tag",
"Master password": "Master password",
"Master password - Tooltip": "Master password - Tooltip",

View File

@@ -126,6 +126,7 @@
"LDAPs": "LDAPы",
"LDAPs - Tooltip": "LDAPs - Подсказки",
"Last name": "Last name",
"Logo": "Logo",
"Logo - Tooltip": "App's image tag",
"Master password": "Мастер-пароль",
"Master password - Tooltip": "Мастер-пароль - Tooltip",

View File

@@ -14,7 +14,7 @@
"Enable signup": "启用注册",
"Enable signup - Tooltip": "是否允许用户注册",
"File uploaded successfully": "文件上传成功",
"Grant types": "Grant types",
"Grant types": "OAuth授权类型",
"Grant types - Tooltip": "选择允许哪些OAuth协议中的Grant types",
"New Application": "添加应用",
"Password ON": "开启密码",
@@ -126,6 +126,7 @@
"LDAPs": "LDAP",
"LDAPs - Tooltip": "LDAPs",
"Last name": "姓氏",
"Logo": "Logo",
"Logo - Tooltip": "应用程序向外展示的图标",
"Master password": "万能密码",
"Master password - Tooltip": "可用来登录该组织下的所有用户,方便管理员以该用户身份登录,以解决技术问题",

View File

@@ -3760,6 +3760,11 @@ core-js@^2.4.0:
resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.19.2, core-js@^3.21.1:
version "3.21.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94"
integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==
core-js@^3.6.5:
version "3.9.1"
resolved "https://registry.npmjs.org/core-js/-/core-js-3.9.1.tgz#cec8de593db8eb2a85ffb0dbdeb312cb6e5460ae"
@@ -9812,6 +9817,18 @@ react-app-polyfill@^2.0.0:
regenerator-runtime "^0.13.7"
whatwg-fetch "^3.4.1"
react-app-polyfill@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz#95221e0a9bd259e5ca6b177c7bb1cb6768f68fd7"
integrity sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==
dependencies:
core-js "^3.19.2"
object-assign "^4.1.1"
promise "^8.1.0"
raf "^3.4.1"
regenerator-runtime "^0.13.9"
whatwg-fetch "^3.6.2"
react-codemirror2@^7.2.1:
version "7.2.1"
resolved "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.2.1.tgz#38dab492fcbe5fb8ebf5630e5bb7922db8d3a10c"
@@ -10158,6 +10175,11 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
regenerator-runtime@^0.13.9:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
regenerator-transform@^0.14.2:
version "0.14.5"
resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
@@ -12155,7 +12177,7 @@ whatwg-encoding@^1.0.5:
dependencies:
iconv-lite "0.4.24"
whatwg-fetch@^3.4.1:
whatwg-fetch@^3.4.1, whatwg-fetch@^3.6.2:
version "3.6.2"
resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==