Compare commits

...

8 Commits

Author SHA1 Message Date
Artem
aafdc546fa fix: panic when creating a user in a non-existent org (#969) 2022-08-06 22:30:56 +08:00
q1anx1
539ca2d731 chore(web): add fix command (#964) 2022-08-05 23:40:04 +08:00
Ryao
ea326b3513 fix: show social buttons on signup page (#962) 2022-08-05 18:59:56 +08:00
Товарищ программист
98ef766fb4 fix: fix webauthn entry cannot add bug (#960)
* fix: fix webauthn

* Update LoginPage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-05 17:43:04 +08:00
Gucheng Wang
e94ada9ea2 Fix new accountItem. 2022-08-05 15:36:07 +08:00
Resulte Lee
4ea482223d feat: add geetest captcha (#953) 2022-08-04 20:55:04 +08:00
Gucheng Wang
d55ae7d1d2 Enable some other DBs 2022-08-04 20:28:09 +08:00
imp2002
d72e00605f fix: updateProviderField when add provider payment (#952) 2022-08-04 19:39:25 +08:00
16 changed files with 319 additions and 133 deletions

82
captcha/geetest.go Normal file
View File

@@ -0,0 +1,82 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package captcha
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
"github.com/casdoor/casdoor/util"
)
const GEETESTCaptchaVerifyUrl = "http://gcaptcha4.geetest.com/validate"
type GEETESTCaptchaProvider struct {
}
func NewGEETESTCaptchaProvider() *GEETESTCaptchaProvider {
captcha := &GEETESTCaptchaProvider{}
return captcha
}
func (captcha *GEETESTCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
pathData, err := url.ParseQuery(token)
if err != nil {
return false, err
}
signToken := util.GetHmacSha256(clientSecret, pathData["lot_number"][0])
formData := make(url.Values)
formData["lot_number"] = []string{pathData["lot_number"][0]}
formData["captcha_output"] = []string{pathData["captcha_output"][0]}
formData["pass_token"] = []string{pathData["pass_token"][0]}
formData["gen_time"] = []string{pathData["gen_time"][0]}
formData["sign_token"] = []string{signToken}
captchaId := pathData["captcha_id"][0]
cli := http.Client{Timeout: time.Second * 5}
resp, err := cli.PostForm(fmt.Sprintf("%s?captcha_id=%s", GEETESTCaptchaVerifyUrl, captchaId), formData)
if err != nil || resp.StatusCode != 200 {
return false, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return false, err
}
type captchaResponse struct {
Result string `json:"result"`
Reason string `json:"reason"`
}
captchaResp := &captchaResponse{}
err = json.Unmarshal(body, captchaResp)
if err != nil {
return false, err
}
if captchaResp.Result == "success" {
return true, nil
}
return false, errors.New(captchaResp.Reason)
}

View File

@@ -27,6 +27,8 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
return NewHCaptchaProvider()
} else if captchaType == "Aliyun Captcha" {
return NewAliyunCaptchaProvider()
} else if captchaType == "GEETEST" {
return NewGEETESTCaptchaProvider()
}
return nil
}

2
go.mod
View File

@@ -14,6 +14,7 @@ require (
github.com/casdoor/goth v1.69.0-FIX2
github.com/casdoor/oss v1.2.0
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-ldap/ldap/v3 v3.3.0
@@ -23,6 +24,7 @@ require (
github.com/google/uuid v1.2.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v0.9.0
github.com/lib/pq v1.8.0
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/qiangmzsx/string-adapter/v2 v2.1.0
github.com/robfig/cron/v3 v3.0.1

2
go.sum
View File

@@ -125,6 +125,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M=
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ=
@@ -173,6 +174,7 @@ github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptG
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=

View File

@@ -21,10 +21,10 @@ import (
"github.com/astaxie/beego"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
//_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
//_ "github.com/lib/pq" // db = postgres
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
"xorm.io/core"
"xorm.io/xorm"
)

View File

@@ -417,6 +417,10 @@ func AddUser(user *User) bool {
}
organization := GetOrganizationByUser(user)
if organization == nil {
return false
}
user.UpdateUserPassword(organization)
user.UpdateUserHash()

View File

@@ -17,7 +17,9 @@ package util
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
)
func GetHmacSha1(keyStr, value string) string {
@@ -28,3 +30,10 @@ func GetHmacSha1(keyStr, value string) string {
return res
}
func GetHmacSha256(key string, data string) string {
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(data))
return hex.EncodeToString(mac.Sum(nil))
}

View File

@@ -39,7 +39,8 @@
"test": "craco test",
"eject": "craco eject",
"crowdin:sync": "crowdin upload && crowdin download",
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\""
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
"fix": "eslint --fix ."
},
"eslintConfig": {
"extends": "react-app"

View File

@@ -38,7 +38,7 @@ class AccountTable extends React.Component {
}
addRow(table) {
let row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true};
let row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true, viewRule: "Public", modifyRule: "Self"};
if (table === undefined) {
table = [];
}

View File

@@ -208,6 +208,8 @@ class ProviderEditPage extends React.Component {
this.updateProviderField("domain", Setting.getFullServerUrl());
} else if (value === "SAML") {
this.updateProviderField("type", "Aliyun IDaaS");
} else if (value === "Payment") {
this.updateProviderField("type", "Alipay");
} else if (value === "Captcha") {
this.updateProviderField("type", "Default");
}

View File

@@ -122,6 +122,10 @@ export const OtherProviderInfo = {
"Aliyun Captcha": {
logo: `${StaticBaseUrl}/img/social_aliyun.png`,
url: "https://help.aliyun.com/product/28308.html",
},
"GEETEST": {
logo: `${StaticBaseUrl}/img/social_geetest.png`,
url: "https://www.geetest.com",
}
}
};
@@ -615,6 +619,7 @@ export function getProviderTypeOptions(category) {
{id: "reCAPTCHA", name: "reCAPTCHA"},
{id: "hCaptcha", name: "hCaptcha"},
{id: "Aliyun Captcha", name: "Aliyun Captcha"},
{id: "GEETEST", name: "GEETEST"},
]);
} else {
return [];

View File

@@ -20,35 +20,13 @@ import * as UserWebauthnBackend from "../backend/UserWebauthnBackend";
import * as AuthBackend from "./AuthBackend";
import * as ApplicationBackend from "../backend/ApplicationBackend";
import * as Provider from "./Provider";
import * as ProviderButton from "./ProviderButton";
import * as Util from "./Util";
import * as Setting from "../Setting";
import SelfLoginButton from "./SelfLoginButton";
import {GithubLoginButton, GoogleLoginButton} from "react-social-login-buttons";
import FacebookLoginButton from "./FacebookLoginButton";
import QqLoginButton from "./QqLoginButton";
import DingTalkLoginButton from "./DingTalkLoginButton";
import GiteeLoginButton from "./GiteeLoginButton";
import WechatLoginButton from "./WechatLoginButton";
import WeiboLoginButton from "./WeiboLoginButton";
import i18next from "i18next";
import LinkedInLoginButton from "./LinkedInLoginButton";
import WeComLoginButton from "./WeComLoginButton";
import LarkLoginButton from "./LarkLoginButton";
import GitLabLoginButton from "./GitLabLoginButton";
import AdfsLoginButton from "./AdfsLoginButton";
import BaiduLoginButton from "./BaiduLoginButton";
import AlipayLoginButton from "./AlipayLoginButton";
import CasdoorLoginButton from "./CasdoorLoginButton";
import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton";
import AzureADLoginButton from "./AzureADLoginButton";
import SlackLoginButton from "./SlackLoginButton";
import SteamLoginButton from "./SteamLoginButton";
import OktaLoginButton from "./OktaLoginButton";
import DouyinLoginButton from "./DouyinLoginButton";
import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput";
import BilibiliLoginButton from "./BilibiliLoginButton";
const {TabPane} = Tabs;
@@ -146,6 +124,16 @@ class LoginPage extends React.Component {
}
onFinish(values) {
if (this.state.loginMethod === "webAuthn") {
let username = this.state.username;
if (username === null || username === "") {
username = values["username"];
}
this.signInWithWebAuthn(username);
return;
}
const application = this.getApplicationObj();
const ths = this;
@@ -260,61 +248,6 @@ class LoginPage extends React.Component {
}
}
getSigninButton(type) {
const text = i18next.t("login:Sign in with {type}").replace("{type}", type);
if (type === "GitHub") {
return <GithubLoginButton text={text} align={"center"} />;
} else if (type === "Google") {
return <GoogleLoginButton text={text} align={"center"} />;
} else if (type === "QQ") {
return <QqLoginButton text={text} align={"center"} />;
} else if (type === "Facebook") {
return <FacebookLoginButton text={text} align={"center"} />;
} else if (type === "Weibo") {
return <WeiboLoginButton text={text} align={"center"} />;
} else if (type === "Gitee") {
return <GiteeLoginButton text={text} align={"center"} />;
} else if (type === "WeChat") {
return <WechatLoginButton text={text} align={"center"} />;
} else if (type === "DingTalk") {
return <DingTalkLoginButton text={text} align={"center"} />;
} else if (type === "LinkedIn") {
return <LinkedInLoginButton text={text} align={"center"} />;
} else if (type === "WeCom") {
return <WeComLoginButton text={text} align={"center"} />;
} else if (type === "Lark") {
return <LarkLoginButton text={text} align={"center"} />;
} else if (type === "GitLab") {
return <GitLabLoginButton text={text} align={"center"} />;
} else if (type === "Adfs") {
return <AdfsLoginButton text={text} align={"center"} />;
} else if (type === "Casdoor") {
return <CasdoorLoginButton text={text} align={"center"} />;
} else if (type === "Baidu") {
return <BaiduLoginButton text={text} align={"center"} />;
} else if (type === "Alipay") {
return <AlipayLoginButton text={text} align={"center"} />;
} else if (type === "Infoflow") {
return <InfoflowLoginButton text={text} align={"center"} />;
} else if (type === "Apple") {
return <AppleLoginButton text={text} align={"center"} />;
} else if (type === "AzureAD") {
return <AzureADLoginButton text={text} align={"center"} />;
} else if (type === "Slack") {
return <SlackLoginButton text={text} align={"center"} />;
} else if (type === "Steam") {
return <SteamLoginButton text={text} align={"center"} />;
} else if (type === "Bilibili") {
return <BilibiliLoginButton text={text} align={"center"} />;
} else if (type === "Okta") {
return <OktaLoginButton text={text} align={"center"} />;
} else if (type === "Douyin") {
return <DouyinLoginButton text={text} align={"center"} />;
}
return text;
}
getSamlUrl(provider) {
const params = new URLSearchParams(this.props.location.search);
let clientId = params.get("client_id");
@@ -332,35 +265,6 @@ class LoginPage extends React.Component {
});
}
renderProviderLogo(provider, application, width, margin, size) {
if (size === "small") {
if (provider.category === "OAuth") {
return (
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "signup")}>
<img width={width} height={width} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={this.getSamlUrl.bind(this, provider)}>
<img width={width} height={width} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
}
} else {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a href={Provider.getAuthUrl(application, provider, "signup")}>
{
this.getSigninButton(provider.type)
}
</a>
</div>
);
}
}
isProviderVisible(providerItem) {
if (this.state.mode === "signup") {
return Setting.isProviderVisibleForSignUp(providerItem);
@@ -499,9 +403,14 @@ class LoginPage extends React.Component {
</Button>
) :
(
<Button type="primary" style={{width: "100%", marginBottom: "5px"}} onClick={() => this.signInWithWebAuthn()}>
{i18next.t("login:Sign in with WebAuthn")}
</Button>
<Button
type="primary"
htmlType="submit"
style={{width: "100%", marginBottom: "5px"}}
disabled={!application.enablePassword}
>
{i18next.t("login:Sign in with WebAuthn")}
</Button>
)
}
{
@@ -511,7 +420,7 @@ class LoginPage extends React.Component {
<Form.Item>
{
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
return this.renderProviderLogo(providerItem.provider, application, 30, 5, "small");
return ProviderButton.renderProviderLogo(providerItem.provider, application, 30, 5, "small");
})
}
</Form.Item>
@@ -532,7 +441,7 @@ class LoginPage extends React.Component {
<br />
{
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
return this.renderProviderLogo(providerItem.provider, application, 40, 10, "big");
return ProviderButton.renderProviderLogo(providerItem.provider, application, 40, 10, "big");
})
}
<div>
@@ -639,14 +548,14 @@ class LoginPage extends React.Component {
);
}
signInWithWebAuthn() {
if (this.state.username === null || this.state.username === "") {
signInWithWebAuthn(username) {
if (username === null || username === "") {
Setting.showMessage("error", "username is required for webauthn login");
return;
}
let application = this.getApplicationObj();
return fetch(`${Setting.ServerUrl}/api/webauthn/signin/begin?owner=${application.organization}&name=${this.state.username}`, {
return fetch(`${Setting.ServerUrl}/api/webauthn/signin/begin?owner=${application.organization}&name=${username}`, {
method: "GET",
credentials: "include"
})
@@ -657,13 +566,13 @@ class LoginPage extends React.Component {
throw credentialRequestOptions.status.msg;
}
credentialRequestOptions.certificate.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.certificate.challenge);
credentialRequestOptions.certificate.allowCredentials.forEach(function(listItem) {
credentialRequestOptions.publicKey.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.publicKey.challenge);
credentialRequestOptions.publicKey.allowCredentials.forEach(function(listItem) {
listItem.id = UserWebauthnBackend.webAuthnBufferDecode(listItem.id);
});
return navigator.credentials.get({
certificate: credentialRequestOptions.certificate
publicKey: credentialRequestOptions.publicKey
});
})
.then((assertion) => {

View File

@@ -0,0 +1,125 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import i18next from "i18next";
import * as Provider from "./Provider";
import {getProviderLogoURL} from "../Setting";
import {GithubLoginButton, GoogleLoginButton} from "react-social-login-buttons";
import QqLoginButton from "./QqLoginButton";
import FacebookLoginButton from "./FacebookLoginButton";
import WeiboLoginButton from "./WeiboLoginButton";
import GiteeLoginButton from "./GiteeLoginButton";
import WechatLoginButton from "./WechatLoginButton";
import DingTalkLoginButton from "./DingTalkLoginButton";
import LinkedInLoginButton from "./LinkedInLoginButton";
import WeComLoginButton from "./WeComLoginButton";
import LarkLoginButton from "./LarkLoginButton";
import GitLabLoginButton from "./GitLabLoginButton";
import AdfsLoginButton from "./AdfsLoginButton";
import CasdoorLoginButton from "./CasdoorLoginButton";
import BaiduLoginButton from "./BaiduLoginButton";
import AlipayLoginButton from "./AlipayLoginButton";
import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton";
import AzureADLoginButton from "./AzureADLoginButton";
import SlackLoginButton from "./SlackLoginButton";
import SteamLoginButton from "./SteamLoginButton";
import BilibiliLoginButton from "./BilibiliLoginButton";
import OktaLoginButton from "./OktaLoginButton";
import DouyinLoginButton from "./DouyinLoginButton";
function getSigninButton(type) {
const text = i18next.t("login:Sign in with {type}").replace("{type}", type);
if (type === "GitHub") {
return <GithubLoginButton text={text} align={"center"} />;
} else if (type === "Google") {
return <GoogleLoginButton text={text} align={"center"} />;
} else if (type === "QQ") {
return <QqLoginButton text={text} align={"center"} />;
} else if (type === "Facebook") {
return <FacebookLoginButton text={text} align={"center"} />;
} else if (type === "Weibo") {
return <WeiboLoginButton text={text} align={"center"} />;
} else if (type === "Gitee") {
return <GiteeLoginButton text={text} align={"center"} />;
} else if (type === "WeChat") {
return <WechatLoginButton text={text} align={"center"} />;
} else if (type === "DingTalk") {
return <DingTalkLoginButton text={text} align={"center"} />;
} else if (type === "LinkedIn") {
return <LinkedInLoginButton text={text} align={"center"} />;
} else if (type === "WeCom") {
return <WeComLoginButton text={text} align={"center"} />;
} else if (type === "Lark") {
return <LarkLoginButton text={text} align={"center"} />;
} else if (type === "GitLab") {
return <GitLabLoginButton text={text} align={"center"} />;
} else if (type === "Adfs") {
return <AdfsLoginButton text={text} align={"center"} />;
} else if (type === "Casdoor") {
return <CasdoorLoginButton text={text} align={"center"} />;
} else if (type === "Baidu") {
return <BaiduLoginButton text={text} align={"center"} />;
} else if (type === "Alipay") {
return <AlipayLoginButton text={text} align={"center"} />;
} else if (type === "Infoflow") {
return <InfoflowLoginButton text={text} align={"center"} />;
} else if (type === "Apple") {
return <AppleLoginButton text={text} align={"center"} />;
} else if (type === "AzureAD") {
return <AzureADLoginButton text={text} align={"center"} />;
} else if (type === "Slack") {
return <SlackLoginButton text={text} align={"center"} />;
} else if (type === "Steam") {
return <SteamLoginButton text={text} align={"center"} />;
} else if (type === "Bilibili") {
return <BilibiliLoginButton text={text} align={"center"} />;
} else if (type === "Okta") {
return <OktaLoginButton text={text} align={"center"} />;
} else if (type === "Douyin") {
return <DouyinLoginButton text={text} align={"center"} />;
}
return text;
}
export function renderProviderLogo(provider, application, width, margin, size) {
if (size === "small") {
if (provider.category === "OAuth") {
return (
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "signup")}>
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
} else if (provider.category === "SAML") {
return (
<a key={provider.displayName} onClick={this.getSamlUrl.bind(this, provider)}>
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName} style={{margin: margin}} />
</a>
);
}
} else {
return (
<div key={provider.displayName} style={{marginBottom: "10px"}}>
<a href={Provider.getAuthUrl(application, provider, "signup")}>
{
getSigninButton(provider.type)
}
</a>
</div>
);
}
}

View File

@@ -17,6 +17,7 @@ import {Link} from "react-router-dom";
import {Button, Checkbox, Col, Form, Input, Modal, Result, Row} from "antd";
import * as Setting from "../Setting";
import * as AuthBackend from "./AuthBackend";
import * as ProviderButton from "./ProviderButton";
import i18next from "i18next";
import * as Util from "./Util";
import {authConfig} from "./Auth";
@@ -179,6 +180,14 @@ class SignupPage extends React.Component {
this.form.current.scrollToField(errorFields[0].name);
}
isProviderVisible(providerItem) {
if (this.state.mode === "signup") {
return Setting.isProviderVisibleForSignUp(providerItem);
} else {
return Setting.isProviderVisibleForSignIn(providerItem);
}
}
renderFormItem(application, signupItem) {
if (!signupItem.visible) {
return null;
@@ -582,6 +591,11 @@ class SignupPage extends React.Component {
{i18next.t("signup:sign in now")}
</a>
</Form.Item>
{
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
return ProviderButton.renderProviderLogo(providerItem.provider, application, 30, 5, "small");
})
}
</Form>
);
}

View File

@@ -21,15 +21,15 @@ export function registerWebauthnCredential() {
})
.then(res => res.json())
.then((credentialCreationOptions) => {
credentialCreationOptions.certificate.challenge = webAuthnBufferDecode(credentialCreationOptions.certificate.challenge);
credentialCreationOptions.certificate.user.id = webAuthnBufferDecode(credentialCreationOptions.certificate.user.id);
if (credentialCreationOptions.certificate.excludeCredentials) {
for (var i = 0; i < credentialCreationOptions.certificate.excludeCredentials.length; i++) {
credentialCreationOptions.certificate.excludeCredentials[i].id = webAuthnBufferDecode(credentialCreationOptions.certificate.excludeCredentials[i].id);
credentialCreationOptions.publicKey.challenge = webAuthnBufferDecode(credentialCreationOptions.publicKey.challenge);
credentialCreationOptions.publicKey.user.id = webAuthnBufferDecode(credentialCreationOptions.publicKey.user.id);
if (credentialCreationOptions.publicKey.excludeCredentials) {
for (var i = 0; i < credentialCreationOptions.publicKey.excludeCredentials.length; i++) {
credentialCreationOptions.publicKey.excludeCredentials[i].id = webAuthnBufferDecode(credentialCreationOptions.publicKey.excludeCredentials[i].id);
}
}
return navigator.credentials.create({
certificate: credentialCreationOptions.certificate
publicKey: credentialCreationOptions.publicKey
});
})
.then((credential) => {

View File

@@ -25,7 +25,7 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
useEffect(() => {
switch (captchaType) {
case "reCAPTCHA":
case "reCAPTCHA": {
const reTimer = setInterval(() => {
if (!window.grecaptcha) {
loadScript("https://recaptcha.net/recaptcha/api.js");
@@ -39,7 +39,8 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}
}, 300);
break;
case "hCaptcha":
}
case "hCaptcha": {
const hTimer = setInterval(() => {
if (!window.hcaptcha) {
loadScript("https://js.hcaptcha.com/1/api.js");
@@ -53,7 +54,8 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}
}, 300);
break;
case "Aliyun Captcha":
}
case "Aliyun Captcha": {
const AWSCTimer = setInterval(() => {
if (!window.AWSC) {
loadScript("https://g.alicdn.com/AWSC/AWSC/awsc.js");
@@ -76,6 +78,33 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}
}, 300);
break;
}
case "GEETEST": {
let getLock = false;
const gTimer = setInterval(() => {
if (!window.initGeetest4) {
loadScript("https://static.geetest.com/v4/gt4.js");
}
if (window.initGeetest4 && siteKey && !getLock) {
const captchaId = String(siteKey);
window.initGeetest4({
captchaId,
product: "float",
}, function(captchaObj) {
if (!getLock) {
captchaObj.appendTo("#captcha");
getLock = true;
}
captchaObj.onSuccess(function() {
const result = captchaObj.getValidate();
onChange(`lot_number=${result.lot_number}&captcha_output=${result.captcha_output}&pass_token=${result.pass_token}&gen_time=${result.gen_time}&captcha_id=${siteKey}`);
});
});
clearInterval(gTimer);
}
}, 500);
break;
}
default:
break;
}