Compare commits

...

229 Commits

Author SHA1 Message Date
19d351d157 feat: allow non-ASCII characters in username (#1235) 2022-10-22 20:46:50 +08:00
d0751bf2fa feat: add arm docker (#1236) 2022-10-22 11:08:29 +08:00
290cc60f00 feat: non root user for casdoor image (#1234)
Signed-off-by: abingcbc <abingcbc626@gmail.com>

Signed-off-by: abingcbc <abingcbc626@gmail.com>
2022-10-21 17:19:58 +08:00
6a1ec51978 feat: fix SSRF when download avatar (#1193) 2022-10-20 14:47:08 +08:00
dffa68cbce feat: fix SAML login error bug (#1228)
* Update LoginPage.js

* fix saml login error
2022-10-20 01:14:38 +08:00
fad209a7a3 Don't check username in UpdateUser() API 2022-10-19 22:50:19 +08:00
8b222ce2e3 Use Steam ID as username 2022-10-18 22:07:20 +08:00
c5293f428d fix: delete this accidentally added files (#1229)
* fix: delete this accidentally added files

* fix: ignore build result

* fix: remove unnecessary asterisk
2022-10-18 21:55:34 +08:00
146aec9ee8 feat: skip username restriction for new users coming from OAuth providers. (#1225) 2022-10-17 18:01:01 +08:00
50a52de856 feat: support database version control (#1221)
* feat: support Database version control

* Update adapter.go

* fix review problems

* Update adapter.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-10-15 17:20:20 +08:00
8f7a8d7d4f fix: translation without reloading (#1215)
* fix: translation without reloading

* fix: language switch
2022-10-12 19:52:02 +08:00
23f3fe1e3c feat: update code format (#1214)
* feat: doc

* feat: doc

* Update model.go

Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-10-12 11:42:14 +08:00
59ff5e02ab fix: Add support for including underscores for username (#1210)
* fix: Add support for including underscores for username

* Update check.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-10-11 19:39:19 +08:00
8d41508d6b fix: center loading in account page (#1209)
* fix: center loading in account page

* Update UserEditPage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-10-11 00:52:08 +08:00
04f70cf012 Improve renderRightDropdown() 2022-10-10 22:53:47 +08:00
83724c73f9 feat: fix pad and mobile views (#1202)
* fix figure width

* fix: pad resolution menu

* feat: drawer style mobile menu

* fix: menu button i18n
2022-10-10 22:37:25 +08:00
33e419e133 Show more items to org admin 2022-10-10 21:58:17 +08:00
b832c304ae Can get owner in getObject() 2022-10-10 20:56:55 +08:00
4c7f6fda37 fix: Add restriction to username when signing up (#1203) 2022-10-10 19:58:02 +08:00
e4a54fe375 fix: disable roles inputbox when model doesn't support RBAC (#1201)
* feat:Support simple ldap server

* fix:fix review problems

* fix:fix review problems

* fix: fix ldapserver crash bug

* Update ldapserver.go

* fix: fix dulpicate go routines

* fix gofumpt problems

* fix: fix UserList error

* feat:disable 'sub role' when model is incorrect

* feat:disable 'sub role' when model is incorrect

* feat:disable 'sub role' when model is incorrect

* delete useless output

* update func name

* Update PermissionEditPage.js

* Update PermissionEditPage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-10-10 00:53:55 +08:00
87da3dad76 Remove useless file 2022-10-09 22:18:38 +08:00
44ad88353f Add error to GetDefaultApplication() 2022-10-09 10:39:33 +08:00
a955fb57d6 feat: fix UserList error (#1194)
* feat:Support simple ldap server

* fix:fix review problems

* fix:fix review problems

* fix: fix ldapserver crash bug

* Update ldapserver.go

* fix: fix dulpicate go routines

* fix gofumpt problems

* fix: fix UserList error
2022-10-08 20:00:45 +08:00
d2960ad66b Fix README typo 2022-10-08 16:00:08 +08:00
5243aabf43 docs: Create SECURITY.md (#1192) 2022-10-07 19:02:35 +08:00
d3a2c2a66e Improve org admin permissions 2022-10-07 16:27:21 +08:00
0a9058a585 Improve user list page 2022-10-07 15:43:50 +08:00
225719810b Update link typo in README 2022-10-06 19:37:00 +08:00
c634d4a891 feat: add some css style for the custom Provider button (#1185)
* fix: add some css style for the custom button

* fix: refactor previous code

* fix: add i18 adaptation

* fix: modifiy the saml codition
2022-10-06 19:28:02 +08:00
3dc01ec85d fix: language widget poisition without border css (#1188) 2022-10-06 17:26:12 +08:00
a7324f1da1 Improve className 2022-10-03 22:45:36 +08:00
6da452d7e0 feat: show language widget in signup and signin pages (#1180) 2022-10-03 22:40:19 +08:00
5abcf913e6 Fix language menu 2022-10-03 22:39:10 +08:00
58455e688e Improve WebAuthnCredentialTable and border radius 2022-10-03 18:46:40 +08:00
4d6f68eddc Improve footer and color 2022-10-03 17:43:19 +08:00
67f3c5a489 Add verificationCode to login method 2022-10-03 15:41:20 +08:00
9c48582e0c feat: fix bugs in webauthn (#1173) 2022-10-01 11:10:55 +08:00
645c631db9 fix: fix the delete file vulnerability issue (#1174) 2022-10-01 00:33:27 +08:00
3128e68df4 Add sendSilentSigninData() 2022-09-30 01:51:58 +08:00
2247c6a883 Add isSelf() in user edit page 2022-09-29 22:24:05 +08:00
04709f731b Update beego to v1.12.11 2022-09-29 19:45:17 +08:00
ebe1887e8b feat: add saml provider error (#1168)
* fix: add saml provider error

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: search

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-09-28 21:09:39 +08:00
a7a8805713 feat: fix dulpicate go routines (#1167)
* feat:Support simple ldap server

* fix:fix review problems

* fix:fix review problems

* fix: fix ldapserver crash bug

* Update ldapserver.go

* fix: fix dulpicate go routines

* fix gofumpt problems
2022-09-28 20:28:00 +08:00
ceabbe27b4 feat: remove p_type in table permission_rule (#1165) 2022-09-27 22:50:27 +08:00
7393b90155 Add enableAutoSignin to application 2022-09-27 20:06:46 +08:00
0098c05fb3 feat: add support for smsbao sms (#1164) 2022-09-27 08:37:55 +08:00
34324d9f72 fix: fix ldapserver crash bug (#1161)
* feat:Support simple ldap server

* fix:fix review problems

* fix:fix review problems

* fix: fix ldapserver crash bug

* Update ldapserver.go
2022-09-26 18:27:17 +08:00
28b381e01e fix: fix webauthn redirection (#1148) 2022-09-25 21:41:52 +08:00
40039e0412 feat: add twilio SMS (#1159) 2022-09-25 17:58:12 +08:00
116420adb2 feat: revert "feat: fix openid address format" (#1158)
This reverts commit a447d64bf2.
2022-09-25 09:58:45 +08:00
07c1e3b836 feat: support simple LDAP server (#1155)
* feat:Support simple ldap server

* fix:fix review problems

* fix:fix review problems
2022-09-24 21:48:29 +08:00
a447d64bf2 fix: openid address format (#1157) 2022-09-24 15:34:11 +08:00
4116b1d305 feat: fix google login flash bug (#1147) 2022-09-23 16:03:09 +08:00
1490044295 fix: add returnUrl for user edit page (#1152)
* feat: add redirect param

Signed-off-by: magicwind <2814461814@qq.com>

* Update UserEditPage.js

Signed-off-by: magicwind <2814461814@qq.com>
Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-09-23 12:01:21 +08:00
79f2af405a fix: check whether to use go proxy in build (#1149) 2022-09-22 22:14:25 +08:00
575a248c41 Add TestGetEmailsForUsers() 2022-09-22 20:51:50 +08:00
7083904634 Improve isValidPersonName() 2022-09-21 21:35:39 +08:00
3d50255060 feat: login background image display (#1145) 2022-09-20 23:06:24 +08:00
e295da774f Improve record list page 2022-09-18 23:11:40 +08:00
a3cee496b4 Add add-record API 2022-09-18 17:35:34 +08:00
084a5c3e6b Show logs to org admin 2022-09-18 16:16:45 +08:00
6670450439 Update CI node-version to 16 2022-09-18 15:52:12 +08:00
e1331f314d Add RequireSignedInUser() 2022-09-18 15:43:49 +08:00
604033aa02 feat: use Casdoor to manage Casbin DB table (#1100)
* feat: use Casdoor to manage Casbin DB table

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: remove trivial codes

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* chore: go fmt

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* feat: support role definition

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: i18n

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: i18n

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-09-14 22:14:13 +08:00
729c20393c fix: missing providers and org in GetDefaultApplication (#1123)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-09-13 22:54:05 +08:00
a90b27b74a Fix admin UI issues 2022-09-13 21:32:18 +08:00
5707e38912 feat: add batchSize to conf (#1120) 2022-09-13 20:31:22 +08:00
ed959bd8c7 feat: improve login page style (#1119)
Signed-off-by: magicwind <2814461814@qq.com>

Signed-off-by: magicwind <2814461814@qq.com>
2022-09-12 00:01:18 +08:00
b6cdc46023 feat: add defaultApplication for Orgnization (#1111)
* feat: add defaultApplication for Orgnization

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: remove redundant codes

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: don't use app-built-in

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: add query param

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* Update organization.go

* Update organization.go

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-09-10 20:41:45 +08:00
c661a57cb2 Support regex in CheckRedirectUriValid() 2022-09-10 13:12:36 +08:00
8456b7f7c4 fix: with error pq: column "DingTalk" of relation "user" does not exist (#1116)
* feat: add dingtalk union_id

* fix: with pg, column Dingtalk of relation user table does not exist.

* Update user_util.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-09-10 13:08:37 +08:00
e8d2906e3c Fix bug in form CSS 2022-09-10 01:33:44 +08:00
1edb91b3a3 feat: custom login form and background (#1107)
* feat: custom login form and background

Signed-off-by: magicwind <2814461814@qq.com>

* feat: costom login form border

* chore: update i18

* Update ApplicationEditPage.js

* Update LoginPage.js

* Update SignupPage.js

* Update LoginPage.js

* Update ApplicationEditPage.js

Signed-off-by: magicwind <2814461814@qq.com>
Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-09-10 00:56:37 +08:00
94b6eb803d Fix WeChat MP login "state too long" bug 2022-09-09 11:43:54 +08:00
cfce5289ed Rename getStateFromQueryParams() and getQueryParamsFromState() 2022-09-09 02:02:32 +08:00
10f1c37730 Fix 403 bug for /api/login/* APIs 2022-09-09 01:54:05 +08:00
6035b98653 feat: add dingtalk union_id (#1110) 2022-09-08 14:44:06 +08:00
e158b58ffa fix: add hidden signal to support chrome extension to auto-signin (#1109)
* feat: add hiden applicationName(support chrome extension to auto recognize applicationName)

* feat: add hiden applicationName for all page

* fix typo

* delete unuseful code

* remove hidden applicationName from login page

* prevent crash if signupApplication is null

* Update App.js

Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-09-07 17:02:28 +08:00
a399184cfc fix: correct edit URL in model list (#1108)
Co-authored-by: Mario Fischer <mario.fischer@inmanet.de>
2022-09-07 00:54:27 +08:00
2f9f946c87 feat: fix GOPROXY bug by exporting environment variable (#1106) 2022-09-05 23:17:39 +08:00
d8b60f838e fix: fix bugs about 3rd-party login in cas flow (#1096) 2022-09-05 23:02:25 +08:00
7599e2715a feat: add demo mode (#1097)
* feat: add demo mode

* feat: add demo mode

* Update app.conf

* Update authz.go

* Update authz.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-09-04 21:20:19 +08:00
35676455bc chore(style): add keyword spacing rule (#1098) 2022-09-04 19:40:30 +08:00
8128671c8c Improve email code 2022-09-04 12:15:07 +08:00
ee54dec3b3 feat: add support for mysubmail (#1095)
* feat: add support for mysubmail

* Update email.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-09-04 12:09:50 +08:00
d278bc9651 Add receiver for Email provider 2022-09-04 11:37:36 +08:00
b23bd0b189 Support SUBMAIL email provider 2022-09-04 11:21:20 +08:00
409be85264 Fix placeholder typo 2022-09-03 18:52:35 +08:00
0395b7e1a9 feat: migrate permission data (#1083)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-09-03 16:45:58 +08:00
4536fd0636 Use app.conf value in getOriginFromHost() 2022-09-03 15:12:34 +08:00
af9ae7dbb7 feat: buildx failed with: EROR: failed to solve: executor failed running [/bin/sh -c ./build.sh]: exit code: 127 (#1089) 2022-09-02 14:50:27 +08:00
e266696b32 feat: add default permission to built-in group (#1087)
* fix: add default permission

* fix: add default permission

* fix: add default permission
2022-09-02 12:03:13 +08:00
e108d26ec7 fix: recover header logo && add styleint check (#1084)
* fix: fix header logo not show

* feat: update lint-staged

feat: add stylelint
2022-08-31 23:26:58 +08:00
349ce7f1d4 fix: refactor build.sh #1081 (#1082)
* fix: Add default access permission for new built-in group users

* fix: Add default access permission for new built-in group users

* fix: File is not `gofumpt`-ed (gofumpt)

* fix: refactor build.sh #1081

* fix: rollback

* fix: newline

* fix: refactor build.sh rename var #1081
2022-08-31 16:08:10 +08:00
8da50b7893 feat: extend managed accounts for get-account api (#1068)
* feat: add get-extend-account api

* feat: extend managed accounts for get-account api

* fix go-linter err

* Use GetApplicationsByOrganizationName
2022-08-30 00:57:27 +08:00
2394c8e2b4 Make sure newStaticBaseUrl is not empty 2022-08-29 21:27:47 +08:00
c62983d734 Use conf.GetConfigString() 2022-08-29 21:26:00 +08:00
5948782cdd fix: fix eslint error in webstorm (#1073) 2022-08-29 15:23:51 +08:00
674d1619dd fix: fix hot update error #1071 (#1072) 2022-08-29 13:45:31 +08:00
11b8b65ca0 feat: update antd and react to latest (#1069) 2022-08-28 23:14:04 +08:00
411d76798d fix: fix upload file security issue (#1063)
* fix: fix upload file security issue

* fix: fix
2022-08-25 11:34:09 +08:00
7b0b426a76 feat: check model grammar when saving and provide a ACL model as init data (#1062)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-08-24 17:21:05 +08:00
a383af0ebc feat: fix token info not contains roles and permissions (#1060)
* fix: fix token info not contains roles and permissions

feat: remove repeated code for obtaining roles and permissions in user controller

* Update user.go

* Update user.go

* Update token.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-24 01:41:26 +08:00
f02875e1b1 fix: enable captcha in the application which is not built-in (#1061) 2022-08-23 23:30:45 +08:00
e2921419b9 Add TestDeployStaticFiles() 2022-08-23 21:17:58 +08:00
42864700ec chore: update badges (#1058) 2022-08-23 13:11:42 +08:00
c1fe547939 fix: not start countdown if SMS fails to send (#1057) 2022-08-22 23:06:41 +08:00
267833d9f9 feat: fix the application edit page bug due to this.props.location.search (#1055) 2022-08-22 15:13:58 +08:00
2d3d1167bb Fix HasPromptPage() for signup items 2022-08-22 11:51:20 +08:00
ef5abdfa8f feat: rollback to fix ci (#1051) 2022-08-22 11:14:51 +08:00
580d43101e fix(i18n): add spanish translations (#1043)
* feat(i18n): add spanish translations

* feat(i18n): add missing translations

* feat(i18n): use new icon flag set

* use document protocol

* fix(i18n): use our static flags
2022-08-22 09:42:28 +08:00
fdf2b880cb feat: click on the app card to log in automatically (#1049) 2022-08-22 01:17:18 +08:00
80a2263b18 fix: fix ci bug: "/go/src/casdoor/.git/refs/heads" not found (#1050) 2022-08-22 01:02:57 +08:00
1f11d22c1c fix: add managed account table for supporting Chrome extension to auto login (#1030)
* feat: add manage accounts table(support chrome extension to auto login)

* fix go lint err

* rename manageAccounts to managedAccounts

* expand up&down buttom column width

* rename ManagedAccountsTable to ManagedAccountTable
2022-08-22 00:25:39 +08:00
b6988286b5 Improve i18n for permission page 2022-08-21 23:17:14 +08:00
64f787fab5 feat: can modify static resource url by app.conf (#1045)
* feat: can modify static resource url by app.conf

Signed-off-by: magicwind <2814461814@qq.com>

* Update static_filter.go

Signed-off-by: magicwind <2814461814@qq.com>
Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-21 21:40:27 +08:00
39c6bd5850 fix: country/region prompted page not show when signin (#1047) 2022-08-21 17:41:07 +08:00
7312c5ce3c Don't check domain for submitPermissionEdit() 2022-08-21 15:28:19 +08:00
0bc5b90218 fix: add country/region selectbox in prompt page (#1022) 2022-08-21 11:12:23 +08:00
f3b3376a3c fix: fix get version error (#1044)
* feat: fix get version error

* feat: more safe

* fix
2022-08-21 10:47:36 +08:00
feec6abd88 fix: fix translations for system info page (#1042) 2022-08-20 23:00:37 +08:00
c50042c85a feat: fix the go.sum error (#1040) 2022-08-20 22:04:37 +08:00
ef4c3833a4 feat: add system info page (#1033)
* feat: add system info page

* feat: add some code

* fix
2022-08-20 21:22:46 +08:00
67a5adf585 feat: replace panic with details json error payload. (#1039)
Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
2022-08-20 21:09:32 +08:00
08a1e7ae32 fix: keep phone/email unique. (#1038)
Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
2022-08-20 12:14:08 +08:00
7d979cbaf0 feat(storage): add support for min.io storage (#1037)
* feat(storage): add support for min.io storage

* fix(minio): use doublequote

* fix(storage): change storage name to MinIO
2022-08-20 11:30:13 +08:00
80c0940e30 feat: initialize the default permission (#1029)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-08-19 11:59:35 +08:00
a4fe2a6485 Add check for submitPermissionEdit() 2022-08-19 01:52:29 +08:00
8e9ed1205b feat: support RBAC with domains model and add adapter to specify the table name for policy storage (#1020)
* feat: support RBAC with domains model and add adapter to specify the table name for policy storage

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix some bugs

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* add i18n

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-08-18 11:49:32 +08:00
a341c65bb1 fix: third-party user may login to the built-in organization (#1024)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-08-17 23:18:38 +08:00
91fa024f0b feat: Mock SMS (#1009)
1. Update go-sms-sender to v0.3.0.
2. Fix: avoid page crash if not found provider info.

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
2022-08-17 22:02:45 +08:00
aedef1eea1 feat(login): add login limit (#1023)
* feat(login): add login limit

* chore: rename vars

* chore: use `string`

* fix: clear the signin error times after succeessfull login

* chore: modify code position
2022-08-17 01:39:53 +08:00
70f2988f09 feat: revert to the original behavior for wrapActionResponse() (#1021)
Revert: 340fbe135d

see: https://github.com/casdoor/casdoor-go-sdk/pull/36.
2022-08-16 00:20:37 +08:00
2dcdfbe6d3 fix: error login logic of mobile phone login (#1017)
* fix: #1016

1. Limit username cannot be digital.
2. Check avoid repeat register with same phone or email.

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

* Update check.go

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-16 00:14:26 +08:00
c92d34e27c Add GetPermissionsBySubmitter() 2022-08-15 14:09:12 +08:00
dfbf7753c3 feat: support RBAC model in permission (#1006)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-08-15 10:24:26 +08:00
ba732b3075 feat: use staticBaseUrl for all static resources (#1015)
* feat: modify system image link

* Update App.less

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-15 09:18:21 +08:00
ca13247572 chore(style): use eqeqeq (#1013) 2022-08-13 11:23:16 +08:00
108fdc174f chore(ci): add linter the check go code style (#991)
* feat(ci): auto format go code

* fix: fix #997

* chore(ci): add go code style linter

* fix: fix cmd error

* chore: add `linter` of needs

* chore: modiy commnet style
2022-08-13 10:57:13 +08:00
a741c5179a chore(style): modify eslint rules (#1011)
* chore(style): use strict rules

* chore: modify position

* chore(style): warn about `console.log` and `==`

* fix: fix `console.log` error

* Update CropperDiv.js

* Update HomePage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-08-13 00:04:18 +08:00
6676cc8ff3 fix: add JTI name to JWT token (#989)
* feat: add jti to jwt

* fix

* fix
2022-08-11 14:32:47 +08:00
13de019d08 chore(ci): use cache to accelerate ci (#1004)
* chore(ci): use cache to accelerate ci

* chore: comment
2022-08-11 10:20:53 +08:00
53ad454962 feat: responsive footer (#1003) 2022-08-10 20:31:42 +08:00
fb203a6f30 feat: delete .env to fix static file path bug (#999) 2022-08-10 12:22:27 +08:00
f716a0985f Add disableSsl to provider. 2022-08-09 23:38:35 +08:00
340fbe135d Fix error in wrapActionResponse() 2022-08-09 23:34:07 +08:00
79119760f2 style: golint (#988) 2022-08-09 16:50:49 +08:00
4dd67a8dcb fix: fix all frontend warnings (#983)
* fix:fix all frontend warnings

* fix:fix all frontend warnings

* fix:fix all frontend warnings

* fix:fix all frontend warnings

* fix:fix all frontend warnings

* fix:fix all frontend warnings
2022-08-09 12:19:56 +08:00
deed857788 chore(style): allow case declarations and ban var (#987)
* chore(style): allow case declarations

* chore(style): ban `var` and prefer `const`
2022-08-08 23:35:24 +08:00
802995ed16 refactor: remove WeChat unionId to properties (#985) 2022-08-08 18:43:12 +08:00
b14554a5ba feat(web): check style when commit (#980)
feat(web): check style when commit
2022-08-08 00:10:31 +08:00
4665ffa759 Update i18n data 2022-08-08 00:02:47 +08:00
f914e8e929 Add permission_enforcer.go 2022-08-07 23:57:06 +08:00
dc33b41107 feat: expose some casbin APIs (#955)
* feat: expose some casbin APIs

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* feat: add BatchEnforce API

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: solve requested changes

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-08-07 23:42:45 +08:00
ee8dd23a56 fix: fixed footer css (#951) 2022-08-07 17:22:52 +08:00
08d0269e30 refactor: New Crowdin translations by Github Action (#974)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-08-07 16:06:52 +08:00
8e5cd18c91 fix: Restrict the request permissions of providers and applications (#970) 2022-08-07 16:05:05 +08:00
32b4d98c2a Add ExtendProductWithProviders(). 2022-08-07 15:45:06 +08:00
2ea58cd639 chore(style): use gofumpt to fmt go code (#967) 2022-08-07 12:26:14 +08:00
45d2745b67 chore(style): add eslint rules: no-unused-imports and no-unused-vars (#976)
* feat(web): no-unused-imports and no-unused-vars

* chore: fix json style
2022-08-07 11:51:53 +08:00
cba338eef2 Merge pull request #973 from qianxi0410/eslint
feat(web): add some eslint rules
2022-08-07 00:41:51 +08:00
c428de6e42 feat: fix some comma dangle 2022-08-07 00:17:27 +08:00
9bca6bb72e feat: no-multi-spacing 2022-08-07 00:06:20 +08:00
cd966116d4 feat: comma dangle 2022-08-06 23:54:56 +08:00
9abf1b9d73 feat: key spacing 2022-08-06 23:47:28 +08:00
6aaba6debd feat: space between infix op 2022-08-06 23:43:09 +08:00
77565712e0 feat: no-multi-empty-lines 2022-08-06 23:38:03 +08:00
d025259db7 feat: indent 2022-08-06 23:36:20 +08:00
aafdc546fa fix: panic when creating a user in a non-existent org (#969) 2022-08-06 22:30:56 +08:00
539ca2d731 chore(web): add fix command (#964) 2022-08-05 23:40:04 +08:00
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
e94ada9ea2 Fix new accountItem. 2022-08-05 15:36:07 +08:00
4ea482223d feat: add geetest captcha (#953) 2022-08-04 20:55:04 +08:00
d55ae7d1d2 Enable some other DBs 2022-08-04 20:28:09 +08:00
d72e00605f fix: updateProviderField when add provider payment (#952) 2022-08-04 19:39:25 +08:00
be74cb621f feat: Support sub-directory (#943)
By adding PUBLIC_URL to relative `.`

Signed-off-by: zzjin <tczzjin@gmail.com>
2022-08-02 00:21:15 +08:00
13404d6035 feat: fix binding after registration causes the page to crash (#945) 2022-08-01 21:08:10 +08:00
afa9c530ad fix: panic triggered when user is nil (#940) 2022-07-31 23:23:36 +08:00
1600615aca Support sqlite3 DB 2022-07-31 18:11:18 +08:00
2bb8491499 fix: unable to get user if profile is private (#936) 2022-07-31 10:54:41 +08:00
293283ed25 feat: add get user by phone (#934)
* fix: check reset phone & email modify rules

* Update verification.go

* Update organization.go

* feat: add get user by phone

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-31 01:02:28 +08:00
9cb519d1e9 fix: Admins should not be allowed to add third-party login for their members (#932)
* feat: admin can unlink the other user

* feat: global admin can unlink other user

* fix
2022-07-30 23:11:02 +08:00
fb9b8f1662 fix: skip the duplicated users when sync users (#928)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-30 22:24:23 +08:00
2fec3f72ae fix: check reset phone & email modify rules (#927)
* fix: check reset phone & email modify rules

* Update verification.go

* Update organization.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-30 18:17:13 +08:00
11695220a8 Use user.GetId() 2022-07-30 17:40:30 +08:00
155660b0d7 feat: get user api return roles and permissions (#929) 2022-07-30 17:31:56 +08:00
1c72f5300c feat: fix 'Enable code sign' is not displayed in the login page (#925) 2022-07-28 23:11:33 +08:00
3dd56195d9 fix: fix the problem of link error (#923) 2022-07-28 21:52:10 +08:00
8865244262 fix: add oauth login auto close page (#915) 2022-07-26 23:03:55 +08:00
3400fa1e9c feat: support local login for non-built-in users (#911)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-26 19:27:24 +08:00
bdc5c92ef0 fix: send code missing parameter & show more detail responseError (#910) 2022-07-25 23:46:38 +08:00
4e3eedf246 feat: fix bug that the default permission prevents admin to login in (#907)
* fix:The certs page is displayed incorrectly

* Translations for each language are added

* Replace the variables certificat with Certificat with certificate and Certificate

* Replace the variables certificat with Certificat with certificate and Certificate

* Variable names are more accurate

* Variable names are more accurate

* Modify the variable name

* fix: Default action prevents admin to login in
2022-07-24 23:36:55 +08:00
8e98fc5a9f feat: rename all publicKey occurrences to certificate (#894)
* fix:The certs page is displayed incorrectly

* Translations for each language are added

* Replace the variables certificat with Certificat with certificate and Certificate

* Replace the variables certificat with Certificat with certificate and Certificate

* Variable names are more accurate

* Variable names are more accurate

* Modify the variable name
2022-07-23 09:40:51 +08:00
6f6159be07 feat: add GET method of logout API (#903) 2022-07-22 21:13:49 +08:00
3e4dbc2dcb fix: URL bug in getUploadFileUrl function 2022-07-20 17:49:11 +08:00
48b5b27982 fix: invalid redirect url after sign up (#896)
* fix: invalid redirect url after sign up

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* Update App.js

* Update Setting.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-19 23:31:17 +08:00
1839252c30 chore(web): sort import members (#895) 2022-07-18 20:57:38 +08:00
1fff1db6a7 fix(web): fix the bug of infinity loop animate when unauthorized (#891)
* fix(web): fix the bug of infinity loop when unauthorized

* fix

* fix

* fix

* Update BaseListPage.js

* Update OrganizationListPage.js

* Update OrganizationListPage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-17 18:20:52 +08:00
a0b0e186b7 Improve i18n code and data. 2022-07-17 17:56:43 +08:00
8c7f235ee1 Fix bug in uploadFile()'s URL. 2022-07-17 14:29:06 +08:00
a0a762aa6f fix: typo in field tag in BilibiliUserInfo (#890) 2022-07-17 11:31:43 +08:00
2eec53a6d0 fix: actions initialized to null and model/resources not updated with the owner (#887)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-16 15:00:42 +08:00
117dec4542 feat: failed to sync keycloak users in the PostgreSQL database (#886)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-16 12:14:35 +08:00
895cdd024d fix: Typo in user model xorm tag (#883) 2022-07-15 12:01:27 +08:00
f0b0891ac9 feat: query user by userId (#879)
* feat: add `getUserByUserId` func

* Update user.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-14 21:46:13 +08:00
10449e89ab Fix owner bug in GetUser(). 2022-07-13 22:56:35 +08:00
6e70f0fc58 Refactor CheckAccessPermission(). 2022-07-13 00:50:32 +08:00
2bca424370 feat: implement access control using casbin (#806)
* feat: implement access control using casbin

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* chore: sort imports

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: remove

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* Update auth.go

Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-07-13 00:34:35 +08:00
de49a45e19 Add escapePath for getUploadFileUrl(). 2022-07-12 23:24:24 +08:00
f7243f879b Fix some JS warnings. 2022-07-12 20:47:11 +08:00
7f3b2500b3 feat: support webauthn (#407)
* feat: support webauthn

* Update init.go

* Update user_webauthn.go

* Update UserEditPage.js

* Update WebauthnCredentialTable.js

* Update LoginPage.js

Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-07-12 20:06:01 +08:00
208dc11d25 fix: set SessionOn always true (#877)
* fix: set SessionOn always true

* Update adapter.go

Co-authored-by: Gucheng <85475922+nomeguy@users.noreply.github.com>
2022-07-11 12:36:20 +08:00
503d244166 feat(web): add lint (#875)
* feat: add lint

* feat: fix lint error

* chore: add ignore file

* chore: close indent
2022-07-10 15:45:55 +08:00
475b6da35a Rename session storage item to signinUrl. 2022-07-10 11:50:48 +08:00
b9404f14dc feat: fix bug of using email provider from wrong application (#869) 2022-07-10 00:40:52 +08:00
0baae87390 feat: fix oauth unknown authority in docker (#871) 2022-07-09 17:36:56 +08:00
06759041a8 Fix socks5Proxy config typo. 2022-07-08 23:24:54 +08:00
cf4e76f9dc feat: add footer to door pages (#868) 2022-07-08 20:36:49 +08:00
81f2d01dc1 fix: fix dockerfile (#866) 2022-07-07 16:10:15 +08:00
61773d3173 fix: support user-defined clientId&Secret (#862) 2022-07-06 19:27:59 +08:00
ec29621547 feat: init from configuration file (#858)
* feat: init from configuration file

* Update init_data.json.template

* Update init_data.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-05 00:36:22 +08:00
b8e324cadf fix: azurad provider (#855) 2022-07-04 16:40:23 +08:00
f37fd6ba87 Fix empty arg bug in getPermanentAvatarUrl(). 2022-07-03 19:31:12 +08:00
b4bf734fe8 fix: fix cors filter (#847)
* fix: fix cors filter

* Update cors_filter.go

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-02 13:45:18 +08:00
f0431701c9 fix: fix OAuth error response (#835)
* fix: fix OAuth error response

* fix: provide more detailed error messages for TokenError
2022-07-01 14:53:34 +08:00
aa5078de15 fix: crowdin kept deleting translations (#843)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-01 10:51:40 +08:00
9a324b2cca fix: Update Crowdin link (#841) 2022-06-30 22:05:20 +08:00
919eaf1df4 fix: fix CORS error after sucessful OPTION (#838) 2022-06-30 21:29:02 +08:00
297 changed files with 24980 additions and 18646 deletions

0
$env
View File

View File

@ -34,7 +34,11 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14.17.0'
node-version: 16
# cache
- uses: c-hive/gha-yarn-cache@v2
with:
directory: ./web
- run: yarn install && CI=false yarn run build
working-directory: ./web
@ -53,11 +57,30 @@ jobs:
go build -race -ldflags "-extldflags '-static'"
working-directory: ./
linter:
name: Go-Linter
runs-on: ubuntu-latest
needs: [ go-tests ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '^1.16.5'
# gen a dummy config file
- run: touch dummy.yml
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --disable-all -c dummy.yml -E=gofumpt --max-same-issues=0 --timeout 5m --modules-download-mode=mod
release-and-push:
name: Release And Push
runs-on: ubuntu-latest
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
needs: [ frontend, backend ]
needs: [ frontend, backend, linter ]
steps:
- name: Checkout
uses: actions/checkout@v2
@ -66,7 +89,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 12
node-version: 16
- name: Fetch Previous version
id: get-previous-tag
@ -102,26 +125,36 @@ jobs:
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
version: latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' &&steps.should_push.outputs.push=='true'
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Push to Docker Hub
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
target: STANDARD
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
- name: Push All In One Version to Docker Hub
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
target: ALLINONE
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest

3
.gitignore vendored
View File

@ -27,3 +27,6 @@ logs/
files/
lastupdate.tmp
commentsRouter*.go
# ignore build result
casdoor

View File

@ -31,7 +31,7 @@ run:
- api
# skip-files:
# - ".*_test\\.go$"
modules-download-mode: vendor
modules-download-mode: mod
# all available settings of specific linters
linters-settings:
lll:

View File

@ -2,7 +2,7 @@ FROM node:16.13.0 AS FRONT
WORKDIR /web
COPY ./web .
RUN yarn config set registry https://registry.npmmirror.com
RUN yarn install && yarn run build
RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build
FROM golang:1.17.5 AS BACK
@ -13,14 +13,27 @@ RUN ./build.sh
FROM alpine:latest AS STANDARD
LABEL MAINTAINER="https://casdoor.org/"
ARG USER=casdoor
WORKDIR /app
COPY --from=BACK /go/src/casdoor/server ./server
COPY --from=BACK /go/src/casdoor/swagger ./swagger
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=FRONT /web/build ./web/build
VOLUME /app/files /app/logs
ENTRYPOINT ["/app/server"]
RUN sed -i 's/https/http/' /etc/apk/repositories
RUN apk add --update sudo
RUN apk add curl
RUN apk add ca-certificates && update-ca-certificates
RUN adduser -D $USER -u 1000 \
&& echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER \
&& chmod 0440 /etc/sudoers.d/$USER \
&& mkdir logs \
&& chown -R $USER:$USER logs
USER 1000
WORKDIR /
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=FRONT --chown=$USER:$USER /web/build ./web/build
ENTRYPOINT ["/server"]
FROM debian:latest AS db
@ -34,9 +47,10 @@ RUN apt update \
FROM db AS ALLINONE
LABEL MAINTAINER="https://casdoor.org/"
ENV MYSQL_ROOT_PASSWORD=123456
RUN apt update
RUN apt install -y ca-certificates && update-ca-certificates
WORKDIR /app
WORKDIR /
COPY --from=BACK /go/src/casdoor/server ./server
COPY --from=BACK /go/src/casdoor/swagger ./swagger
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh

View File

@ -8,7 +8,7 @@
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
</a>
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casbin/jcasbin/workflows/build/badge.svg?style=flat-square">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casdoor.svg">
@ -42,47 +42,34 @@
</a>
</p>
## Online demo
- International: https://door.casdoor.org (read-only)
- Asian mirror: https://door.casdoor.com (read-only)
- Asian mirror: https://demo.casdoor.com (read-write, will restore for every 5 minutes)
## Documentation
- International: https://casdoor.org
- Asian mirror: https://docs.casdoor.cn
- Asian mirror: https://casdoor.cn
## Install
- By source code: https://casdoor.org/docs/basic/server-installation
- By Docker: https://casdoor.org/docs/basic/try-with-docker
## How to connect to Casdoor?
https://casdoor.org/docs/how-to-connect/overview
## Casdoor Public API
- Docs: https://casdoor.org/docs/basic/public-api
- Swagger: https://door.casdoor.com/swagger
## Integrations
https://casdoor.org/docs/integration/apisix
https://casdoor.org/docs/category/integrations
## How to contact?
@ -90,17 +77,13 @@ https://casdoor.org/docs/integration/apisix
- Forum: https://forum.casbin.com
- Contact: https://tawk.to/chat/623352fea34c2456412b8c51/1fuc7od6e
## Contribute
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
### I18n translation
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-web) as translating platform and i18next as translating tool. When you add some words using i18next in the ```web/``` directory, please remember to add what you have added to the ```web/src/locales/en/data.json``` file.
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the `web/` directory, please remember to add what you have added to the `web/src/locales/en/data.json` file.
## License

9
SECURITY.md Normal file
View File

@ -0,0 +1,9 @@
# Security Policy
## Reporting a Vulnerability
We are grateful for security researchers and users reporting a vulnerability to us first. To ensure that your request is handled in a timely manner and we can keep users safe, please follow the below guidelines.
- **Please do not report security vulnerabilities directly on GitHub.**
- To report a vulnerability, please email [admin@casdoor.org](admin@casdoor.org).

View File

@ -15,10 +15,14 @@
package authz
import (
"fmt"
"strings"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v2"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
stringadapter "github.com/qiangmzsx/string-adapter/v2"
)
@ -28,7 +32,7 @@ func InitAuthz() {
var err error
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
a, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), "casbin_rule", tableNamePrefix, true)
a, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName()+conf.GetConfigString("dbName"), "casbin_rule", tableNamePrefix, true)
if err != nil {
panic(err)
}
@ -68,7 +72,7 @@ m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
Enforcer.ClearPolicy()
//if len(Enforcer.GetPolicy()) == 0 {
// if len(Enforcer.GetPolicy()) == 0 {
if true {
ruleText := `
p, built-in, *, *, *, *, *
@ -78,20 +82,22 @@ p, *, *, POST, /api/get-email-and-phone, *, *
p, *, *, POST, /api/login, *, *
p, *, *, GET, /api/get-app-login, *, *
p, *, *, POST, /api/logout, *, *
p, *, *, GET, /api/logout, *, *
p, *, *, GET, /api/get-account, *, *
p, *, *, GET, /api/userinfo, *, *
p, *, *, *, /api/login/oauth, *, *
p, *, *, GET, /api/get-application, *, *
p, *, *, GET, /api/get-applications, *, *
p, *, *, GET, /api/get-organization-applications, *, *
p, *, *, GET, /api/get-user, *, *
p, *, *, GET, /api/get-user-application, *, *
p, *, *, GET, /api/get-resources, *, *
p, *, *, GET, /api/get-records, *, *
p, *, *, GET, /api/get-product, *, *
p, *, *, POST, /api/buy-product, *, *
p, *, *, GET, /api/get-payment, *, *
p, *, *, POST, /api/update-payment, *, *
p, *, *, POST, /api/invoice-payment, *, *
p, *, *, GET, /api/get-providers, *, *
p, *, *, POST, /api/notify-payment, *, *
p, *, *, POST, /api/unlink, *, *
p, *, *, POST, /api/set-password, *, *
p, *, *, POST, /api/send-verification-code, *, *
@ -105,6 +111,9 @@ p, *, *, GET, /api/get-saml-login, *, *
p, *, *, POST, /api/acs, *, *
p, *, *, GET, /api/saml/metadata, *, *
p, *, *, *, /cas, *, *
p, *, *, *, /api/webauthn, *, *
p, *, *, GET, /api/get-release, *, *
p, *, *, GET, /api/get-default-application, *, *
`
sa := stringadapter.NewAdapter(ruleText)
@ -125,6 +134,18 @@ p, *, *, *, /cas, *, *
}
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if conf.IsDemoMode() {
if !isAllowedInDemoMode(subOwner, subName, method, urlPath, objOwner, objName) {
return false
}
}
userId := fmt.Sprintf("%s/%s", subOwner, subName)
user := object.GetUser(userId)
if user != nil && user.IsAdmin && subOwner == objOwner {
return true
}
res, err := Enforcer.Enforce(subOwner, subName, method, urlPath, objOwner, objName)
if err != nil {
panic(err)
@ -132,3 +153,22 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
return res
}
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if method == "POST" {
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/send-verification-code" {
return true
} else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information
if subOwner == objOwner && subName == objName && !(subOwner == "built-in" && subName == "admin") {
return true
}
return false
} else {
return false
}
}
// If method equals GET
return true
}

View File

@ -1,11 +1,11 @@
#!/bin/bash
#try to connect to google to determine whether user need to use proxy
curl www.google.com -o /dev/null --connect-timeout 5 2 > /dev/null
curl www.google.com -o /dev/null --connect-timeout 5 2> /dev/null
if [ $? == 0 ]
then
echo "Successfully connected to Google, no need to use Go proxy"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .
else
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOPROXY=https://goproxy.cn,direct go build -ldflags="-w -s" -o server .
export GOPROXY="https://goproxy.cn,direct"
fi
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"sort"
@ -31,8 +31,7 @@ import (
const AliyunCaptchaVerifyUrl = "http://afs.aliyuncs.com"
type AliyunCaptchaProvider struct {
}
type AliyunCaptchaProvider struct{}
func NewAliyunCaptchaProvider() *AliyunCaptchaProvider {
captcha := &AliyunCaptchaProvider{}
@ -81,7 +80,7 @@ func (captcha *AliyunCaptchaProvider) VerifyCaptcha(token, clientSecret string)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
}

View File

@ -16,8 +16,7 @@ package captcha
import "github.com/casdoor/casdoor/object"
type DefaultCaptchaProvider struct {
}
type DefaultCaptchaProvider struct{}
func NewDefaultCaptchaProvider() *DefaultCaptchaProvider {
captcha := &DefaultCaptchaProvider{}

81
captcha/geetest.go Normal file
View File

@ -0,0 +1,81 @@
// 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"
"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 := io.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

@ -17,7 +17,7 @@ package captcha
import (
"encoding/json"
"errors"
"io/ioutil"
"io"
"net/http"
"net/url"
"strings"
@ -25,8 +25,7 @@ import (
const HCaptchaVerifyUrl = "https://hcaptcha.com/siteverify"
type HCaptchaProvider struct {
}
type HCaptchaProvider struct{}
func NewHCaptchaProvider() *HCaptchaProvider {
captcha := &HCaptchaProvider{}
@ -44,7 +43,7 @@ func (captcha *HCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
}

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
}

View File

@ -17,7 +17,7 @@ package captcha
import (
"encoding/json"
"errors"
"io/ioutil"
"io"
"net/http"
"net/url"
"strings"
@ -25,8 +25,7 @@ import (
const ReCaptchaVerifyUrl = "https://recaptcha.net/recaptcha/api/siteverify"
type ReCaptchaProvider struct {
}
type ReCaptchaProvider struct{}
func NewReCaptchaProvider() *ReCaptchaProvider {
captcha := &ReCaptchaProvider{}
@ -44,7 +43,7 @@ func (captcha *ReCaptchaProvider) VerifyCaptcha(token, clientSecret string) (boo
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
}

View File

@ -1,7 +1,6 @@
appname = casdoor
httpport = 8000
runmode = dev
SessionOn = true
copyrequestbody = true
driverName = mysql
dataSourceName = root:123456@tcp(localhost:3306)/
@ -12,8 +11,12 @@ redisEndpoint =
defaultStorageProvider =
isCloudIntranet = false
authState = "casdoor"
sock5Proxy = "127.0.0.1:10808"
socks5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10
initScore = 2000
logPostOnly = true
origin =
origin =
staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false
batchSize = 100
ldapServerPort = 389

View File

@ -21,14 +21,35 @@ import (
"strconv"
"strings"
"github.com/astaxie/beego"
"github.com/beego/beego"
)
func init() {
// this array contains the beego configuration items that may be modified via env
presetConfigItems := []string{"httpport", "appname"}
for _, key := range presetConfigItems {
if value, ok := os.LookupEnv(key); ok {
err := beego.AppConfig.Set(key, value)
if err != nil {
panic(err)
}
}
}
}
func GetConfigString(key string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return beego.AppConfig.String(key)
res := beego.AppConfig.String(key)
if res == "" {
if key == "staticBaseUrl" {
res = "https://cdn.casbin.org"
}
}
return res
}
func GetConfigBool(key string) (bool, error) {
@ -47,17 +68,7 @@ func GetConfigInt64(key string) (int64, error) {
return num, err
}
func init() {
//this array contains the beego configuration items that may be modified via env
var presetConfigItems = []string{"httpport", "appname"}
for _, key := range presetConfigItems {
if value, ok := os.LookupEnv(key); ok {
beego.AppConfig.Set(key, value)
}
}
}
func GetBeegoConfDataSourceName() string {
func GetConfigDataSourceName() string {
dataSourceName := GetConfigString("dataSourceName")
runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
@ -72,3 +83,15 @@ func GetBeegoConfDataSourceName() string {
return dataSourceName
}
func IsDemoMode() bool {
return strings.ToLower(GetConfigString("isDemoMode")) == "true"
}
func GetConfigBatchSize() int {
res, err := strconv.Atoi(GetConfigString("batchSize"))
if err != nil {
res = 100
}
return res
}

View File

@ -11,13 +11,14 @@
// 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 conf
import (
"os"
"testing"
"github.com/astaxie/beego"
"github.com/beego/beego"
"github.com/stretchr/testify/assert"
)
@ -32,7 +33,7 @@ func TestGetConfString(t *testing.T) {
{"Should be return value", "key", "value"},
}
//do some set up job
// do some set up job
os.Setenv("appname", "casbin")
os.Setenv("key", "value")
@ -58,7 +59,7 @@ func TestGetConfInt(t *testing.T) {
{"Should be return 8000", "verificationCodeTimeout", 10},
}
//do some set up job
// do some set up job
os.Setenv("httpport", "8001")
err := beego.LoadAppConfig("ini", "app.conf")
@ -79,13 +80,9 @@ func TestGetConfBool(t *testing.T) {
input string
expected interface{}
}{
{"Should be return false", "SessionOn", false},
{"Should be return false", "copyrequestbody", true},
}
//do some set up job
os.Setenv("SessionOn", "false")
err := beego.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {

View File

@ -105,7 +105,8 @@ func (c *ApiController) Signup() {
var form RequestForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
@ -156,6 +157,12 @@ func (c *ApiController) Signup() {
username = id
}
initScore, err := getInitScore()
if err != nil {
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
return
}
user := &object.User{
Owner: form.Organization,
Name: username,
@ -171,7 +178,7 @@ func (c *ApiController) Signup() {
Affiliation: form.Affiliation,
IdCard: form.IdCard,
Region: form.Region,
Score: getInitScore(),
Score: initScore,
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,
@ -217,7 +224,7 @@ func (c *ApiController) Signup() {
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
userId := fmt.Sprintf("%s/%s", user.Owner, user.Name)
userId := user.GetId()
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
c.ResponseOk(userId)
@ -228,7 +235,7 @@ func (c *ApiController) Signup() {
// @Tag Login API
// @Description logout the current user
// @Success 200 {object} controllers.Response The Response object
// @router /logout [post]
// @router /logout [get,post]
func (c *ApiController) Logout() {
user := c.GetSessionUsername()
util.LogInfo(c.Ctx, "API: [%s] logged out", user)
@ -251,15 +258,14 @@ func (c *ApiController) Logout() {
// @Success 200 {object} controllers.Response The Response object
// @router /get-account [get]
func (c *ApiController) GetAccount() {
userId, ok := c.RequireSignedIn()
user, ok := c.RequireSignedInUser()
if !ok {
return
}
user := object.GetUser(userId)
if user == nil {
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
return
managedAccounts := c.Input().Get("managedAccounts")
if managedAccounts == "1" {
user = object.ExtendManagedAccountsWithUser(user)
}
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
@ -274,6 +280,7 @@ func (c *ApiController) GetAccount() {
c.ServeJSON()
}
// GetUserinfo
// UserInfo
// @Title UserInfo
// @Tag Account API
@ -281,18 +288,16 @@ func (c *ApiController) GetAccount() {
// @Success 200 {object} object.Userinfo The Response object
// @router /userinfo [get]
func (c *ApiController) GetUserinfo() {
userId, ok := c.RequireSignedIn()
user, ok := c.RequireSignedInUser()
if !ok {
return
}
scope, aud := c.GetSessionOidc()
host := c.Ctx.Request.Host
resp, err := object.GetUserInfo(userId, scope, aud, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = resp
userInfo := object.GetUserInfo(user, scope, aud, host)
c.Data["json"] = userInfo
c.ServeJSON()
}

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"fmt"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -94,6 +94,28 @@ func (c *ApiController) GetUserApplication() {
c.ServeJSON()
}
// GetOrganizationApplications
// @Title GetOrganizationApplications
// @Tag Application API
// @Description get the detail of the organization's application
// @Param organization query string true "The organization name"
// @Success 200 {array} object.Application The Response object
// @router /get-organization-applications [get]
func (c *ApiController) GetOrganizationApplications() {
userId := c.GetSessionUsername()
owner := c.Input().Get("owner")
organization := c.Input().Get("organization")
if organization == "" {
c.ResponseError("Parameter organization is missing")
return
}
applications := object.GetApplicationsByOrganizationName(owner, organization)
c.Data["json"] = object.GetMaskedApplications(applications, userId)
c.ServeJSON()
}
// UpdateApplication
// @Title UpdateApplication
// @Tag Application API
@ -108,7 +130,8 @@ func (c *ApiController) UpdateApplication() {
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
@ -126,7 +149,8 @@ func (c *ApiController) AddApplication() {
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
@ -144,7 +168,8 @@ func (c *ApiController) DeleteApplication() {
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteApplication(&application))

View File

@ -44,12 +44,22 @@ func tokenToResponse(token *object.Token) *Response {
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()
allowed, err := object.CheckAccessPermission(userId, application)
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
if !allowed {
c.ResponseError("Unauthorized operation")
return
}
if form.Type == ResponseTypeLogin {
c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
@ -75,7 +85,7 @@ 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
} 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 {
@ -83,7 +93,6 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
token, _ := object.GetTokenByUser(application, user, scope, c.Ctx.Request.Host)
resp = tokenToResponse(token)
}
} else if form.Type == ResponseTypeSaml { // saml flow
res, redirectUrl, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
if err != nil {
@ -92,7 +101,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: redirectUrl}
} else if form.Type == ResponseTypeCas {
//not oauth but CAS SSO protocol
// not oauth but CAS SSO protocol
service := c.Input().Get("service")
resp = wrapErrorResponse(nil)
if service != "" {
@ -109,7 +118,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}
} else {
resp = wrapErrorResponse(fmt.Errorf("Unknown response type: %s", form.Type))
resp = wrapErrorResponse(fmt.Errorf("unknown response type: %s", form.Type))
}
// if user did not check auto signin
@ -335,7 +344,7 @@ func (c *ApiController) Login() {
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
}
if user != nil && user.IsDeleted == false {
if user != nil && !user.IsDeleted {
// Sign in via OAuth (want to sign up but already have account)
if user.IsForbidden {
@ -375,6 +384,12 @@ func (c *ApiController) Login() {
properties := map[string]string{}
properties["no"] = strconv.Itoa(len(object.GetUsers(application.Organization)) + 2)
initScore, err := getInitScore()
if err != nil {
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
return
}
user = &object.User{
Owner: application.Organization,
Name: userInfo.Username,
@ -385,7 +400,7 @@ func (c *ApiController) Login() {
Avatar: userInfo.AvatarUrl,
Address: []string{},
Email: userInfo.Email,
Score: getInitScore(),
Score: initScore,
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,
@ -419,7 +434,7 @@ func (c *ApiController) Login() {
} else if provider.Category == "SAML" {
resp = &Response{Status: "error", Msg: "The account does not exist"}
}
//resp = &Response{Status: "ok", Msg: "", Data: res}
// resp = &Response{Status: "ok", Msg: "", Data: res}
} else { // form.Method != "signup"
userId := c.GetSessionUsername()
if userId == "" {

View File

@ -18,16 +18,19 @@ import (
"strings"
"time"
"github.com/astaxie/beego"
"github.com/beego/beego"
"github.com/beego/beego/logs"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// ApiController
// controller for handlers under /api uri
type ApiController struct {
beego.Controller
}
// RootController
// controller for handlers directly under / (root)
type RootController struct {
ApiController
@ -56,6 +59,7 @@ func (c *ApiController) IsGlobalAdmin() bool {
func (c *ApiController) GetSessionUsername() string {
// check if user session expired
sessionData := c.GetSessionData()
if sessionData != nil &&
sessionData.ExpireTime != 0 &&
sessionData.ExpireTime < time.Now().Unix() {
@ -118,7 +122,8 @@ func (c *ApiController) GetSessionData() *SessionData {
sessionData := &SessionData{}
err := util.JsonToStruct(session.(string), sessionData)
if err != nil {
panic(err)
logs.Error("GetSessionData failed, error: %s", err)
return nil
}
return sessionData

View File

@ -31,7 +31,7 @@ const (
InvalidProxyCallback string = "INVALID_PROXY_CALLBACK"
InvalidTicket string = "INVALID_TICKET"
InvalidService string = "INVALID_SERVICE"
InteralError string = "INTERNAL_ERROR"
InternalError string = "INTERNAL_ERROR"
UnauthorizedService string = "UNAUTHORIZED_SERVICE"
)
@ -44,14 +44,13 @@ func (c *RootController) CasValidate() {
return
}
if ok, response, issuedService, _ := object.GetCasTokenByTicket(ticket); ok {
//check whether service is the one for which we previously issued token
// check whether service is the one for which we previously issued token
if issuedService == service {
c.Ctx.Output.Body([]byte(fmt.Sprintf("yes\n%s\n", response.User)))
return
}
}
//token not found
// token not found
c.Ctx.Output.Body([]byte("no\n"))
}
@ -83,41 +82,41 @@ func (c *RootController) CasP3ServiceAndProxyValidate() {
Xmlns: "http://www.yale.edu/tp/cas",
}
//check whether all required parameters are met
// check whether all required parameters are met
if service == "" || ticket == "" {
c.sendCasAuthenticationResponseErr(InvalidRequest, "service and ticket must exist", format)
return
}
ok, response, issuedService, userId := object.GetCasTokenByTicket(ticket)
//find the token
// find the token
if ok {
//check whether service is the one for which we previously issued token
// check whether service is the one for which we previously issued token
if strings.HasPrefix(service, issuedService) {
serviceResponse.Success = response
} else {
//service not match
// service not match
c.sendCasAuthenticationResponseErr(InvalidService, fmt.Sprintf("service %s and %s does not match", service, issuedService), format)
return
}
} else {
//token not found
// token not found
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
return
}
if pgtUrl != "" && serviceResponse.Failure == nil {
//that means we are in proxy web flow
// that means we are in proxy web flow
pgt := object.StoreCasTokenForPgt(serviceResponse.Success, service, userId)
pgtiou := serviceResponse.Success.ProxyGrantingTicket
//todo: check whether it is https
// todo: check whether it is https
pgtUrlObj, err := url.Parse(pgtUrl)
if pgtUrlObj.Scheme != "https" {
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, "callback is not https", format)
return
}
//make a request to pgturl passing pgt and pgtiou
// make a request to pgturl passing pgt and pgtiou
if err != nil {
c.sendCasAuthenticationResponseErr(InteralError, err.Error(), format)
c.sendCasAuthenticationResponseErr(InternalError, err.Error(), format)
return
}
param := pgtUrlObj.Query()
@ -127,13 +126,13 @@ func (c *RootController) CasP3ServiceAndProxyValidate() {
request, err := http.NewRequest("GET", pgtUrlObj.String(), nil)
if err != nil {
c.sendCasAuthenticationResponseErr(InteralError, err.Error(), format)
c.sendCasAuthenticationResponseErr(InternalError, err.Error(), format)
return
}
resp, err := http.DefaultClient.Do(request)
if err != nil || !(resp.StatusCode >= 200 && resp.StatusCode < 400) {
//failed to send request
// failed to send request
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, err.Error(), format)
return
}
@ -184,7 +183,6 @@ func (c *RootController) CasProxy() {
c.Data["xml"] = serviceResponse
c.ServeXML()
}
}
func (c *RootController) SamlValidate() {
@ -216,7 +214,7 @@ func (c *RootController) SamlValidate() {
return
}
envelopReponse := struct {
envelopResponse := struct {
XMLName xml.Name `xml:"SOAP-ENV:Envelope"`
Xmlns string `xml:"xmlns:SOAP-ENV"`
Body struct {
@ -224,15 +222,15 @@ func (c *RootController) SamlValidate() {
Content string `xml:",innerxml"`
}
}{}
envelopReponse.Xmlns = "http://schemas.xmlsoap.org/soap/envelope/"
envelopReponse.Body.Content = response
envelopResponse.Xmlns = "http://schemas.xmlsoap.org/soap/envelope/"
envelopResponse.Body.Content = response
data, err := xml.Marshal(envelopReponse)
data, err := xml.Marshal(envelopResponse)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Ctx.Output.Body([]byte(data))
c.Ctx.Output.Body(data)
}
func (c *RootController) sendCasProxyResponseErr(code, msg, format string) {

View File

@ -0,0 +1,94 @@
// 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 controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
func (c *ApiController) GetCasbinAdapters() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetCasbinAdapters(owner)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCasbinAdapterCount(owner, field, value)))
adapters := object.GetPaginationCasbinAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(adapters, paginator.Nums())
}
}
func (c *ApiController) GetCasbinAdapter() {
id := c.Input().Get("id")
c.Data["json"] = object.GetCasbinAdapter(id)
c.ServeJSON()
}
func (c *ApiController) UpdateCasbinAdapter() {
id := c.Input().Get("id")
var casbinAdapter object.CasbinAdapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateCasbinAdapter(id, &casbinAdapter))
c.ServeJSON()
}
func (c *ApiController) AddCasbinAdapter() {
var casbinAdapter object.CasbinAdapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddCasbinAdapter(&casbinAdapter))
c.ServeJSON()
}
func (c *ApiController) DeleteCasbinAdapter() {
var casbinAdapter object.CasbinAdapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteCasbinAdapter(&casbinAdapter))
c.ServeJSON()
}
func (c *ApiController) SyncPolicies() {
id := c.Input().Get("id")
adapter := object.GetCasbinAdapter(id)
c.Data["json"] = object.SyncPolicies(adapter)
c.ServeJSON()
}

View File

@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -48,6 +48,7 @@ func (c *ApiController) GetCerts() {
}
}
// GetCert
// @Title GetCert
// @Tag Cert API
// @Description get cert
@ -61,6 +62,7 @@ func (c *ApiController) GetCert() {
c.ServeJSON()
}
// UpdateCert
// @Title UpdateCert
// @Tag Cert API
// @Description update cert
@ -74,13 +76,15 @@ func (c *ApiController) UpdateCert() {
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateCert(id, &cert))
c.ServeJSON()
}
// AddCert
// @Title AddCert
// @Tag Cert API
// @Description add cert
@ -91,13 +95,15 @@ func (c *ApiController) AddCert() {
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddCert(&cert))
c.ServeJSON()
}
// DeleteCert
// @Title DeleteCert
// @Tag Cert API
// @Description delete cert
@ -108,7 +114,8 @@ func (c *ApiController) DeleteCert() {
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteCert(&cert))

90
controllers/enforcer.go Normal file
View File

@ -0,0 +1,90 @@
// 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 controllers
import (
"encoding/json"
"github.com/casdoor/casdoor/object"
)
func (c *ApiController) Enforce() {
userId := c.GetSessionUsername()
if userId == "" {
c.ResponseError("Please sign in first")
return
}
var permissionRule object.PermissionRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.Enforce(userId, &permissionRule)
c.ServeJSON()
}
func (c *ApiController) BatchEnforce() {
userId := c.GetSessionUsername()
if userId == "" {
c.ResponseError("Please sign in first")
return
}
var permissionRules []object.PermissionRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.BatchEnforce(userId, permissionRules)
c.ServeJSON()
}
func (c *ApiController) GetAllObjects() {
userId := c.GetSessionUsername()
if userId == "" {
c.ResponseError("Please sign in first")
return
}
c.Data["json"] = object.GetAllObjects(userId)
c.ServeJSON()
}
func (c *ApiController) GetAllActions() {
userId := c.GetSessionUsername()
if userId == "" {
c.ResponseError("Please sign in first")
return
}
c.Data["json"] = object.GetAllActions(userId)
c.ServeJSON()
}
func (c *ApiController) GetAllRoles() {
userId := c.GetSessionUsername()
if userId == "" {
c.ResponseError("Please sign in first")
return
}
c.Data["json"] = object.GetAllRoles(userId)
c.ServeJSON()
}

View File

@ -30,7 +30,7 @@ type LdapServer struct {
}
type LdapResp struct {
//Groups []LdapRespGroup `json:"groups"`
// Groups []LdapRespGroup `json:"groups"`
Users []object.LdapRespUser `json:"users"`
}
@ -44,6 +44,7 @@ type LdapSyncResp struct {
Failed []object.LdapRespUser `json:"failed"`
}
// GetLdapUser
// @Tag Account API
// @Title GetLdapser
// @router /get-ldap-user [post]
@ -88,7 +89,7 @@ func (c *ApiController) GetLdapUser() {
Uid: user.Uid,
Cn: user.Cn,
GroupId: user.GidNumber,
//GroupName: groupsMap[user.GidNumber].Cn,
// GroupName: groupsMap[user.GidNumber].Cn,
Uuid: user.Uuid,
Email: util.GetMaxLenStr(user.Mail, user.Email, user.EmailAddress),
Phone: util.GetMaxLenStr(user.TelephoneNumber, user.Mobile, user.MobileTelephoneNumber),
@ -100,6 +101,7 @@ func (c *ApiController) GetLdapUser() {
c.ServeJSON()
}
// GetLdaps
// @Tag Account API
// @Title GetLdaps
// @router /get-ldaps [post]
@ -110,6 +112,7 @@ func (c *ApiController) GetLdaps() {
c.ServeJSON()
}
// GetLdap
// @Tag Account API
// @Title GetLdap
// @router /get-ldap [post]
@ -125,6 +128,7 @@ func (c *ApiController) GetLdap() {
c.ServeJSON()
}
// AddLdap
// @Tag Account API
// @Title AddLdap
// @router /add-ldap [post]
@ -159,6 +163,7 @@ func (c *ApiController) AddLdap() {
c.ServeJSON()
}
// UpdateLdap
// @Tag Account API
// @Title UpdateLdap
// @router /update-ldap [post]
@ -186,6 +191,7 @@ func (c *ApiController) UpdateLdap() {
c.ServeJSON()
}
// DeleteLdap
// @Tag Account API
// @Title DeleteLdap
// @router /delete-ldap [post]
@ -193,7 +199,8 @@ func (c *ApiController) DeleteLdap() {
var ldap object.Ldap
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
object.GetLdapAutoSynchronizer().StopAutoSync(ldap.Id)
@ -201,6 +208,7 @@ func (c *ApiController) DeleteLdap() {
c.ServeJSON()
}
// SyncLdapUsers
// @Tag Account API
// @Title SyncLdapUsers
// @router /sync-ldap-users [post]
@ -210,7 +218,8 @@ func (c *ApiController) SyncLdapUsers() {
var users []object.LdapRespUser
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
object.UpdateLdapSyncTime(ldapId)
@ -223,6 +232,7 @@ func (c *ApiController) SyncLdapUsers() {
c.ServeJSON()
}
// CheckLdapUsersExist
// @Tag Account API
// @Title CheckLdapUserExist
// @router /check-ldap-users-exist [post]
@ -231,7 +241,8 @@ func (c *ApiController) CheckLdapUsersExist() {
var uuids []string
err := json.Unmarshal(c.Ctx.Input.RequestBody, &uuids)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
exist := object.CheckLdapUuidExist(owner, uuids)

118
controllers/ldapserver.go Normal file
View File

@ -0,0 +1,118 @@
// 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 controllers
import (
"fmt"
"log"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"github.com/forestmgy/ldapserver"
"github.com/lor00x/goldap/message"
)
func StartLdapServer() {
server := ldapserver.NewServer()
routes := ldapserver.NewRouteMux()
routes.Bind(handleBind)
routes.Search(handleSearch).Label(" SEARCH****")
server.Handle(routes)
server.ListenAndServe("0.0.0.0:" + conf.GetConfigString("ldapServerPort"))
}
func handleBind(w ldapserver.ResponseWriter, m *ldapserver.Message) {
r := m.GetBindRequest()
res := ldapserver.NewBindResponse(ldapserver.LDAPResultSuccess)
if r.AuthenticationChoice() == "simple" {
bindusername, bindorg, err := object.GetNameAndOrgFromDN(string(r.Name()))
if err != "" {
log.Printf("Bind failed ,ErrMsg=%s", err)
res.SetResultCode(ldapserver.LDAPResultInvalidDNSyntax)
res.SetDiagnosticMessage("bind failed ErrMsg: " + err)
w.Write(res)
return
}
bindpassword := string(r.AuthenticationSimple())
binduser, err := object.CheckUserPassword(bindorg, bindusername, bindpassword)
if err != "" {
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
res.SetResultCode(ldapserver.LDAPResultInvalidCredentials)
res.SetDiagnosticMessage("invalid credentials ErrMsg: " + err)
w.Write(res)
return
}
if bindorg == "built-in" {
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
} else if binduser.IsAdmin {
m.Client.IsOrgAdmin = true
}
m.Client.IsAuthenticated = true
m.Client.UserName = bindusername
m.Client.OrgName = bindorg
} else {
res.SetResultCode(ldapserver.LDAPResultAuthMethodNotSupported)
res.SetDiagnosticMessage("Authentication method not supported,Please use Simple Authentication")
}
w.Write(res)
}
func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
res := ldapserver.NewSearchResultDoneResponse(ldapserver.LDAPResultSuccess)
if !m.Client.IsAuthenticated {
res.SetResultCode(ldapserver.LDAPResultUnwillingToPerform)
w.Write(res)
return
}
r := m.GetSearchRequest()
if r.FilterString() == "(objectClass=*)" {
w.Write(res)
return
}
name, org, errCode := object.GetUserNameAndOrgFromBaseDnAndFilter(string(r.BaseObject()), r.FilterString())
if errCode != ldapserver.LDAPResultSuccess {
res.SetResultCode(errCode)
w.Write(res)
return
}
// Handle Stop Signal (server stop / client disconnected / Abandoned request....)
select {
case <-m.Done:
log.Print("Leaving handleSearch...")
return
default:
}
users, errCode := object.GetFilteredUsers(m, name, org)
if errCode != ldapserver.LDAPResultSuccess {
res.SetResultCode(errCode)
w.Write(res)
return
}
for i := 0; i < len(users); i++ {
user := users[i]
dn := fmt.Sprintf("cn=%s,%s", user.DisplayName, string(r.BaseObject()))
e := ldapserver.NewSearchResultEntry(dn)
e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Name))
e.AddAttribute("email", message.AttributeValue(user.Email))
e.AddAttribute("mobile", message.AttributeValue(user.Phone))
// e.AddAttribute("postalAddress", message.AttributeValue(user.Address[0]))
w.Write(e)
}
w.Write(res)
}

View File

@ -21,14 +21,15 @@ import (
)
type LinkForm struct {
ProviderType string `json:"providerType"`
ProviderType string `json:"providerType"`
User object.User `json:"user"`
}
// Unlink ...
// @router /unlink [post]
// @Tag Login API
func (c *ApiController) Unlink() {
userId, ok := c.RequireSignedIn()
user, ok := c.RequireSignedInUser()
if !ok {
return
}
@ -36,20 +37,59 @@ func (c *ApiController) Unlink() {
var form LinkForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
providerType := form.ProviderType
user := object.GetUser(userId)
value := object.GetUserField(user, providerType)
// the user will be unlinked from the provider
unlinkedUser := form.User
if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin {
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
c.ResponseError("You are not the global admin, you can't unlink other users")
return
}
if user.Id == unlinkedUser.Id && !user.IsGlobalAdmin {
// if the user is unlinking themselves, should check the provider can be unlinked, if not, we should return an error.
application := object.GetApplicationByUser(user)
if application == nil {
c.ResponseError("You can't unlink yourself, you are not a member of any application")
return
}
if len(application.Providers) == 0 {
c.ResponseError("This application has no providers")
return
}
provider := application.GetProviderItemByType(providerType)
if provider == nil {
c.ResponseError("This application has no providers of type " + providerType)
return
}
if !provider.CanUnlink {
c.ResponseError("This provider can't be unlinked")
return
}
}
// only two situations can happen here
// 1. the user is the global admin
// 2. the user is unlinking themselves and provider can be unlinked
value := object.GetUserField(&unlinkedUser, providerType)
if value == "" {
c.ResponseError("Please link first", value)
return
}
object.ClearUserOAuthProperties(user, providerType)
object.ClearUserOAuthProperties(&unlinkedUser, providerType)
object.LinkUserAccount(user, providerType, "")
object.LinkUserAccount(&unlinkedUser, providerType, "")
c.ResponseOk()
}

View File

@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -76,7 +76,8 @@ func (c *ApiController) UpdateModel() {
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateModel(id, &model))
@ -94,7 +95,8 @@ func (c *ApiController) AddModel() {
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddModel(&model))
@ -112,7 +114,8 @@ func (c *ApiController) DeleteModel() {
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteModel(&model))

View File

@ -16,6 +16,7 @@ package controllers
import "github.com/casdoor/casdoor/object"
// GetOidcDiscovery
// @Title GetOidcDiscovery
// @Tag OIDC API
// @Description Get Oidc Discovery
@ -27,6 +28,7 @@ func (c *RootController) GetOidcDiscovery() {
c.ServeJSON()
}
// GetJwks
// @Title GetJwks
// @Tag OIDC API
// @Success 200 {object} jose.JSONWebKey

View File

@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -76,7 +76,8 @@ func (c *ApiController) UpdateOrganization() {
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization))
@ -94,7 +95,8 @@ func (c *ApiController) AddOrganization() {
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
@ -112,9 +114,31 @@ func (c *ApiController) DeleteOrganization() {
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteOrganization(&organization))
c.ServeJSON()
}
// GetDefaultApplication ...
// @Title GetDefaultApplication
// @Tag Organization API
// @Description get default application
// @Param id query string true "organization id"
// @Success 200 {object} Response The Response object
// @router /get-default-application [get]
func (c *ApiController) GetDefaultApplication() {
userId := c.GetSessionUsername()
id := c.Input().Get("id")
application, err := object.GetDefaultApplication(id)
if err != nil {
c.ResponseError(err.Error())
return
}
maskedApplication := object.GetMaskedApplication(application, userId)
c.ResponseOk(maskedApplication)
}

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"fmt"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -67,6 +67,7 @@ func (c *ApiController) GetUserPayments() {
c.ResponseOk(payments)
}
// GetPayment
// @Title GetPayment
// @Tag Payment API
// @Description get payment
@ -80,6 +81,7 @@ func (c *ApiController) GetPayment() {
c.ServeJSON()
}
// UpdatePayment
// @Title UpdatePayment
// @Tag Payment API
// @Description update payment
@ -93,13 +95,15 @@ func (c *ApiController) UpdatePayment() {
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdatePayment(id, &payment))
c.ServeJSON()
}
// AddPayment
// @Title AddPayment
// @Tag Payment API
// @Description add payment
@ -110,13 +114,15 @@ func (c *ApiController) AddPayment() {
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddPayment(&payment))
c.ServeJSON()
}
// DeletePayment
// @Title DeletePayment
// @Tag Payment API
// @Description delete payment
@ -127,13 +133,15 @@ func (c *ApiController) DeletePayment() {
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeletePayment(&payment))
c.ServeJSON()
}
// NotifyPayment
// @Title NotifyPayment
// @Tag Payment API
// @Description notify payment
@ -152,13 +160,15 @@ func (c *ApiController) NotifyPayment() {
if ok {
_, err := c.Ctx.ResponseWriter.Write([]byte("success"))
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
} else {
panic(fmt.Errorf("NotifyPayment() failed: %v", ok))
}
}
// InvoicePayment
// @Title InvoicePayment
// @Tag Payment API
// @Description invoice payment

View File

@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -48,6 +48,24 @@ func (c *ApiController) GetPermissions() {
}
}
// GetPermissionsBySubmitter
// @Title GetPermissionsBySubmitter
// @Tag Permission API
// @Description get permissions by submitter
// @Success 200 {array} object.Permission The Response object
// @router /get-permissions-by-submitter [get]
func (c *ApiController) GetPermissionsBySubmitter() {
user, ok := c.RequireSignedInUser()
if !ok {
return
}
permissions := object.GetPermissionsBySubmitter(user.Owner, user.Name)
c.ResponseOk(permissions, len(permissions))
return
}
// GetPermission
// @Title GetPermission
// @Tag Permission API
// @Description get permission
@ -61,6 +79,7 @@ func (c *ApiController) GetPermission() {
c.ServeJSON()
}
// UpdatePermission
// @Title UpdatePermission
// @Tag Permission API
// @Description update permission
@ -74,13 +93,15 @@ func (c *ApiController) UpdatePermission() {
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdatePermission(id, &permission))
c.ServeJSON()
}
// AddPermission
// @Title AddPermission
// @Tag Permission API
// @Description add permission
@ -91,13 +112,15 @@ func (c *ApiController) AddPermission() {
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddPermission(&permission))
c.ServeJSON()
}
// DeletePermission
// @Title DeletePermission
// @Tag Permission API
// @Description delete permission
@ -108,7 +131,8 @@ func (c *ApiController) DeletePermission() {
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeletePermission(&permission))

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"fmt"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -49,6 +49,7 @@ func (c *ApiController) GetProducts() {
}
}
// GetProduct
// @Title GetProduct
// @Tag Product API
// @Description get product
@ -58,10 +59,14 @@ func (c *ApiController) GetProducts() {
func (c *ApiController) GetProduct() {
id := c.Input().Get("id")
c.Data["json"] = object.GetProduct(id)
product := object.GetProduct(id)
object.ExtendProductWithProviders(product)
c.Data["json"] = product
c.ServeJSON()
}
// UpdateProduct
// @Title UpdateProduct
// @Tag Product API
// @Description update product
@ -75,13 +80,15 @@ func (c *ApiController) UpdateProduct() {
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProduct(id, &product))
c.ServeJSON()
}
// AddProduct
// @Title AddProduct
// @Tag Product API
// @Description add product
@ -92,13 +99,15 @@ func (c *ApiController) AddProduct() {
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddProduct(&product))
c.ServeJSON()
}
// DeleteProduct
// @Title DeleteProduct
// @Tag Product API
// @Description delete product
@ -109,13 +118,15 @@ func (c *ApiController) DeleteProduct() {
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProduct(&product))
c.ServeJSON()
}
// BuyProduct
// @Title BuyProduct
// @Tag Product API
// @Description buy product

View File

@ -16,7 +16,8 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -47,6 +48,7 @@ func (c *ApiController) GetProviders() {
}
}
// GetProvider
// @Title GetProvider
// @Tag Provider API
// @Description get provider
@ -60,6 +62,7 @@ func (c *ApiController) GetProvider() {
c.ServeJSON()
}
// UpdateProvider
// @Title UpdateProvider
// @Tag Provider API
// @Description update provider
@ -73,13 +76,15 @@ func (c *ApiController) UpdateProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
c.ServeJSON()
}
// AddProvider
// @Title AddProvider
// @Tag Provider API
// @Description add provider
@ -90,13 +95,15 @@ func (c *ApiController) AddProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
c.ServeJSON()
}
// DeleteProvider
// @Title DeleteProvider
// @Tag Provider API
// @Description delete provider
@ -107,7 +114,8 @@ func (c *ApiController) DeleteProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))

View File

@ -15,7 +15,9 @@
package controllers
import (
"github.com/astaxie/beego/utils/pagination"
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -29,6 +31,11 @@ import (
// @Success 200 {object} object.Record The Response object
// @router /get-records [get]
func (c *ApiController) GetRecords() {
organization, ok := c.RequireAdmin()
if !ok {
return
}
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
@ -40,8 +47,9 @@ func (c *ApiController) GetRecords() {
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRecordCount(field, value)))
records := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder)
filterRecord := &object.Record{Organization: organization}
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRecordCount(field, value, filterRecord)))
records := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
c.ResponseOk(records, paginator.Nums())
}
}
@ -59,9 +67,29 @@ func (c *ApiController) GetRecordsByFilter() {
record := &object.Record{}
err := util.JsonToStruct(body, record)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.GetRecordsByField(record)
c.ServeJSON()
}
// AddRecord
// @Title AddRecord
// @Tag Record API
// @Description add a record
// @Param body body object.Record true "The details of the record"
// @Success 200 {object} controllers.Response The Response object
// @router /add-record [post]
func (c *ApiController) AddRecord() {
var record object.Record
err := json.Unmarshal(c.Ctx.Input.RequestBody, &record)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddRecord(&record))
c.ServeJSON()
}

View File

@ -22,11 +22,12 @@ import (
"mime"
"path/filepath"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetResources
// @router /get-resources [get]
// @Tag Resource API
// @Title GetResources
@ -50,6 +51,7 @@ func (c *ApiController) GetResources() {
}
}
// GetResource
// @Tag Resource API
// @Title GetResource
// @router /get-resource [get]
@ -60,6 +62,7 @@ func (c *ApiController) GetResource() {
c.ServeJSON()
}
// UpdateResource
// @Tag Resource API
// @Title UpdateResource
// @router /update-resource [post]
@ -69,13 +72,15 @@ func (c *ApiController) UpdateResource() {
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateResource(id, &resource))
c.ServeJSON()
}
// AddResource
// @Tag Resource API
// @Title AddResource
// @router /add-resource [post]
@ -83,13 +88,15 @@ func (c *ApiController) AddResource() {
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddResource(&resource))
c.ServeJSON()
}
// DeleteResource
// @Tag Resource API
// @Title DeleteResource
// @router /delete-resource [post]
@ -97,7 +104,8 @@ func (c *ApiController) DeleteResource() {
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
provider, _, ok := c.GetProviderFromContext("Storage")
@ -115,6 +123,7 @@ func (c *ApiController) DeleteResource() {
c.ServeJSON()
}
// UploadResource
// @Tag Resource API
// @Title UploadResource
// @router /upload-resource [post]

View File

@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -48,6 +48,7 @@ func (c *ApiController) GetRoles() {
}
}
// GetRole
// @Title GetRole
// @Tag Role API
// @Description get role
@ -61,6 +62,7 @@ func (c *ApiController) GetRole() {
c.ServeJSON()
}
// UpdateRole
// @Title UpdateRole
// @Tag Role API
// @Description update role
@ -74,13 +76,15 @@ func (c *ApiController) UpdateRole() {
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateRole(id, &role))
c.ServeJSON()
}
// AddRole
// @Title AddRole
// @Tag Role API
// @Description add role
@ -91,13 +95,15 @@ func (c *ApiController) AddRole() {
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddRole(&role))
c.ServeJSON()
}
// DeleteRole
// @Title DeleteRole
// @Tag Role API
// @Description delete role
@ -108,7 +114,8 @@ func (c *ApiController) DeleteRole() {
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteRole(&role))

View File

@ -16,7 +16,8 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -47,6 +48,7 @@ func (c *ApiController) GetSyncers() {
}
}
// GetSyncer
// @Title GetSyncer
// @Tag Syncer API
// @Description get syncer
@ -60,6 +62,7 @@ func (c *ApiController) GetSyncer() {
c.ServeJSON()
}
// UpdateSyncer
// @Title UpdateSyncer
// @Tag Syncer API
// @Description update syncer
@ -73,13 +76,15 @@ func (c *ApiController) UpdateSyncer() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer))
c.ServeJSON()
}
// AddSyncer
// @Title AddSyncer
// @Tag Syncer API
// @Description add syncer
@ -90,13 +95,15 @@ func (c *ApiController) AddSyncer() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddSyncer(&syncer))
c.ServeJSON()
}
// DeleteSyncer
// @Title DeleteSyncer
// @Tag Syncer API
// @Description delete syncer
@ -107,13 +114,15 @@ func (c *ApiController) DeleteSyncer() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSyncer(&syncer))
c.ServeJSON()
}
// RunSyncer
// @Title RunSyncer
// @Tag Syncer API
// @Description run syncer

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 controllers
import (
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
type SystemInfo struct {
MemoryUsed uint64 `json:"memory_used"`
MemoryTotal uint64 `json:"memory_total"`
CpuUsage []float64 `json:"cpu_usage"`
}
// GetSystemInfo
// @Title GetSystemInfo
// @Tag System API
// @Description get user's system info
// @Param id query string true "The id of the user"
// @Success 200 {object} object.SystemInfo The Response object
// @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() {
id := c.GetString("id")
if id == "" {
id = c.GetSessionUsername()
}
user := object.GetUser(id)
if user == nil || !user.IsGlobalAdmin {
c.ResponseError("You are not authorized to access this resource")
return
}
cpuUsage, err := util.GetCpuUsage()
if err != nil {
c.ResponseError(err.Error())
return
}
memoryUsed, memoryTotal, err := util.GetMemoryUsage()
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = SystemInfo{
CpuUsage: cpuUsage,
MemoryUsed: memoryUsed,
MemoryTotal: memoryTotal,
}
c.ServeJSON()
}
// GitRepoVersion
// @Title GitRepoVersion
// @Tag System API
// @Description get local github repo's latest release version info
// @Success 200 {string} local latest version hash of casdoor
// @router /get-release [get]
func (c *ApiController) GitRepoVersion() {
version, err := util.GetGitRepoVersion()
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = version
c.ServeJSON()
}

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"net/http"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -79,7 +79,8 @@ func (c *ApiController) UpdateToken() {
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token))
@ -97,7 +98,8 @@ func (c *ApiController) AddToken() {
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddToken(&token))
@ -115,7 +117,8 @@ func (c *ApiController) DeleteToken() {
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteToken(&token))
@ -165,6 +168,8 @@ func (c *ApiController) GetOAuthCode() {
// @Param client_secret query string true "OAuth client secret"
// @Param code query string true "OAuth code"
// @Success 200 {object} object.TokenWrapper The Response object
// @Success 400 {object} object.TokenError The Response object
// @Success 401 {object} object.TokenError The Response object
// @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() {
grantType := c.Input().Get("grant_type")
@ -200,6 +205,7 @@ func (c *ApiController) GetOAuthToken() {
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, tag, avatar)
c.SetTokenErrorHttpStatus()
c.ServeJSON()
}
@ -213,6 +219,8 @@ func (c *ApiController) GetOAuthToken() {
// @Param client_id query string true "OAuth client id"
// @Param client_secret query string false "OAuth client secret"
// @Success 200 {object} object.TokenWrapper The Response object
// @Success 400 {object} object.TokenError The Response object
// @Success 401 {object} object.TokenError The Response object
// @router /login/oauth/refresh_token [post]
func (c *ApiController) RefreshToken() {
grantType := c.Input().Get("grant_type")
@ -235,6 +243,7 @@ func (c *ApiController) RefreshToken() {
}
c.Data["json"] = object.RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
c.SetTokenErrorHttpStatus()
c.ServeJSON()
}
@ -249,7 +258,7 @@ func (c *ApiController) RefreshToken() {
// @router /login/oauth/logout [get]
func (c *ApiController) TokenLogout() {
token := c.Input().Get("id_token_hint")
flag, application := object.DeleteTokenByAceessToken(token)
flag, application := object.DeleteTokenByAccessToken(token)
redirectUri := c.Input().Get("post_logout_redirect_uri")
state := c.Input().Get("state")
if application != nil && object.CheckRedirectUriValid(application, redirectUri) {
@ -263,13 +272,16 @@ func (c *ApiController) TokenLogout() {
// 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.
// 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
// @Success 400 {object} object.TokenError The Response object
// @Success 401 {object} object.TokenError The Response object
// @router /login/oauth/introspect [post]
func (c *ApiController) IntrospectToken() {
tokenValue := c.Input().Get("token")
@ -279,12 +291,21 @@ func (c *ApiController) IntrospectToken() {
clientSecret = c.Input().Get("client_secret")
if clientId == "" || clientSecret == "" {
c.ResponseError("empty clientId or clientSecret")
c.Data["json"] = &object.TokenError{
Error: object.InvalidRequest,
}
c.SetTokenErrorHttpStatus()
c.ServeJSON()
return
}
}
application := object.GetApplicationByClientId(clientId)
if application == nil || application.ClientSecret != clientSecret {
c.ResponseError("invalid application or wrong clientSecret")
c.Data["json"] = &object.TokenError{
Error: object.InvalidClient,
}
c.SetTokenErrorHttpStatus()
return
}
token := object.GetTokenByTokenAndApplication(tokenValue, application.Name)

View File

@ -19,7 +19,7 @@ import (
"fmt"
"strings"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -80,19 +80,27 @@ func (c *ApiController) GetUsers() {
// @Title GetUser
// @Tag User API
// @Description get user
// @Param id query string true "The id of the user"
// @Param id query string true "The id of the user"
// @Param owner query string false "The owner of the user"
// @Param email query string false "The email of the user"
// @Param phone query string false "The phone of the user"
// @Success 200 {object} object.User The Response object
// @router /get-user [get]
func (c *ApiController) GetUser() {
id := c.Input().Get("id")
owner := c.Input().Get("owner")
email := c.Input().Get("email")
userOwner, _ := util.GetOwnerAndNameFromId(id)
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", userOwner))
phone := c.Input().Get("phone")
userId := c.Input().Get("userId")
owner := c.Input().Get("owner")
if owner == "" {
owner, _ = util.GetOwnerAndNameFromId(id)
}
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", owner))
if !organization.IsProfilePublic {
requestUserId := c.GetSessionUsername()
hasPermission, err := object.CheckUserPermission(requestUserId, id, false)
hasPermission, err := object.CheckUserPermission(requestUserId, id, owner, false)
if !hasPermission {
c.ResponseError(err.Error())
return
@ -100,12 +108,19 @@ func (c *ApiController) GetUser() {
}
var user *object.User
if email == "" {
user = object.GetUser(id)
} else {
switch {
case email != "":
user = object.GetUserByEmail(owner, email)
case phone != "":
user = object.GetUserByPhone(owner, phone)
case userId != "":
user = object.GetUserByUserId(owner, userId)
default:
user = object.GetUser(id)
}
object.ExtendUserWithRolesAndPermissions(user)
c.Data["json"] = object.GetMaskedUser(user)
c.ServeJSON()
}
@ -129,7 +144,8 @@ func (c *ApiController) UpdateUser() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
if user.DisplayName == "" {
@ -163,7 +179,14 @@ func (c *ApiController) AddUser() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
msg := object.CheckUsername(user.Name)
if msg != "" {
c.ResponseError(msg)
return
}
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
@ -181,7 +204,8 @@ func (c *ApiController) DeleteUser() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
@ -200,7 +224,8 @@ func (c *ApiController) GetEmailAndPhone() {
var form RequestForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
user := object.GetUserByFields(form.Organization, form.Username)
@ -246,7 +271,7 @@ func (c *ApiController) SetPassword() {
requestUserId := c.GetSessionUsername()
userId := fmt.Sprintf("%s/%s", userOwner, userName)
hasPermission, err := object.CheckUserPermission(requestUserId, userId, true)
hasPermission, err := object.CheckUserPermission(requestUserId, userId, userOwner, true)
if !hasPermission {
c.ResponseError(err.Error())
return
@ -278,6 +303,7 @@ func (c *ApiController) SetPassword() {
c.ServeJSON()
}
// CheckUserPassword
// @Title CheckUserPassword
// @router /check-user-password [post]
// @Tag User API
@ -285,7 +311,8 @@ func (c *ApiController) CheckUserPassword() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
_, msg := object.CheckUserPassword(user.Owner, user.Name, user.Password)

View File

@ -24,17 +24,18 @@ import (
"github.com/casdoor/casdoor/util"
)
func saveFile(path string, file *multipart.File) {
func saveFile(path string, file *multipart.File) (err error) {
f, err := os.Create(path)
if err != nil {
panic(err)
return err
}
defer f.Close()
_, err = io.Copy(f, *file)
if err != nil {
panic(err)
return err
}
return nil
}
func (c *ApiController) UploadUsers() {
@ -43,13 +44,18 @@ func (c *ApiController) UploadUsers() {
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
path := util.GetUploadXlsxPath(fileId)
util.EnsureFileFolderExists(path)
saveFile(path, &file)
err = saveFile(path, &file)
if err != nil {
c.ResponseError(err.Error())
return
}
affected := object.UploadUsers(owner, fileId)
if affected {

View File

@ -23,9 +23,8 @@ import (
"github.com/casdoor/casdoor/util"
)
// ResponseOk ...
func (c *ApiController) ResponseOk(data ...interface{}) {
resp := Response{Status: "ok"}
// ResponseJsonData ...
func (c *ApiController) ResponseJsonData(resp *Response, data ...interface{}) {
switch len(data) {
case 2:
resp.Data2 = data[1]
@ -37,18 +36,33 @@ func (c *ApiController) ResponseOk(data ...interface{}) {
c.ServeJSON()
}
// ResponseOk ...
func (c *ApiController) ResponseOk(data ...interface{}) {
resp := &Response{Status: "ok"}
c.ResponseJsonData(resp, data...)
}
// ResponseError ...
func (c *ApiController) ResponseError(error string, data ...interface{}) {
resp := Response{Status: "error", Msg: error}
switch len(data) {
case 2:
resp.Data2 = data[1]
fallthrough
case 1:
resp.Data = data[0]
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
}
// SetTokenErrorHttpStatus ...
func (c *ApiController) SetTokenErrorHttpStatus() {
_, ok := c.Data["json"].(*object.TokenError)
if ok {
if c.Data["json"].(*object.TokenError).Error == object.InvalidClient {
c.Ctx.Output.SetStatus(401)
c.Ctx.Output.Header("WWW-Authenticate", "Basic realm=\"OAuth2\"")
} else {
c.Ctx.Output.SetStatus(400)
}
}
_, ok = c.Data["json"].(*object.TokenWrapper)
if ok {
c.Ctx.Output.SetStatus(200)
}
c.Data["json"] = resp
c.ServeJSON()
}
// RequireSignedIn ...
@ -61,13 +75,36 @@ func (c *ApiController) RequireSignedIn() (string, bool) {
return userId, true
}
func getInitScore() int {
score, err := strconv.Atoi(conf.GetConfigString("initScore"))
if err != nil {
panic(err)
// RequireSignedInUser ...
func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
userId, ok := c.RequireSignedIn()
if !ok {
return nil, false
}
return score
user := object.GetUser(userId)
if user == nil {
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
return nil, false
}
return user, true
}
// RequireAdmin ...
func (c *ApiController) RequireAdmin() (string, bool) {
user, ok := c.RequireSignedInUser()
if !ok {
return "", false
}
if user.Owner == "built-in" {
return "", true
}
return user.Owner, true
}
func getInitScore() (int, error) {
return strconv.Atoi(conf.GetConfigString("initScore"))
}
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {

View File

@ -42,15 +42,31 @@ func (c *ApiController) getCurrentUser() *object.User {
func (c *ApiController) SendVerificationCode() {
destType := c.Ctx.Request.Form.Get("type")
dest := c.Ctx.Request.Form.Get("dest")
orgId := c.Ctx.Request.Form.Get("organizationId")
checkType := c.Ctx.Request.Form.Get("checkType")
checkId := c.Ctx.Request.Form.Get("checkId")
checkKey := c.Ctx.Request.Form.Get("checkKey")
checkUser := c.Ctx.Request.Form.Get("checkUser")
applicationId := c.Ctx.Request.Form.Get("applicationId")
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
if len(destType) == 0 || len(dest) == 0 || len(orgId) == 0 || !strings.Contains(orgId, "/") || len(checkType) == 0 {
c.ResponseError("Missing parameter.")
if destType == "" {
c.ResponseError("Missing parameter: type.")
return
}
if dest == "" {
c.ResponseError("Missing parameter: dest.")
return
}
if applicationId == "" {
c.ResponseError("Missing parameter: applicationId.")
return
}
if !strings.Contains(applicationId, "/") {
c.ResponseError("Wrong parameter: applicationId.")
return
}
if checkType == "" {
c.ResponseError("Missing parameter: checkType.")
return
}
@ -74,18 +90,18 @@ func (c *ApiController) SendVerificationCode() {
}
user := c.getCurrentUser()
organization := object.GetOrganization(orgId)
application := object.GetApplicationByOrganizationName(organization.Name)
application := object.GetApplication(applicationId)
organization := object.GetOrganization(fmt.Sprintf("%s/%s", application.Owner, application.Organization))
if checkUser == "true" && user == nil && object.GetUserByFields(organization.Name, dest) == nil {
c.ResponseError("Please login first")
return
}
sendResp := errors.New("Invalid dest type")
sendResp := errors.New("invalid dest type")
if user == nil && checkUser != "" && checkUser != "true" {
_, name := util.GetOwnerAndNameFromId(orgId)
name := application.Organization
user = object.GetUser(fmt.Sprintf("%s/%s", name, checkUser))
}
switch destType {
@ -108,13 +124,12 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError("Invalid phone number")
return
}
org := object.GetOrganization(orgId)
if org == nil {
c.ResponseError("Missing parameter.")
if organization == nil {
c.ResponseError("The organization doesn't exist.")
return
}
dest = fmt.Sprintf("+%s%s", org.PhonePrefix, dest)
dest = fmt.Sprintf("+%s%s", organization.PhonePrefix, dest)
provider := application.GetSmsProvider()
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, dest)
}
@ -133,17 +148,11 @@ func (c *ApiController) SendVerificationCode() {
// @Title ResetEmailOrPhone
// @router /api/reset-email-or-phone [post]
func (c *ApiController) ResetEmailOrPhone() {
userId, ok := c.RequireSignedIn()
user, ok := c.RequireSignedInUser()
if !ok {
return
}
user := object.GetUser(userId)
if user == nil {
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
return
}
destType := c.Ctx.Request.Form.Get("type")
dest := c.Ctx.Request.Form.Get("dest")
code := c.Ctx.Request.Form.Get("code")
@ -153,13 +162,35 @@ func (c *ApiController) ResetEmailOrPhone() {
}
checkDest := dest
org := object.GetOrganizationByUser(user)
if destType == "phone" {
org := object.GetOrganizationByUser(user)
phoneItem := object.GetAccountItemByName("Phone", org)
if phoneItem == nil {
c.ResponseError("Unable to get the phone modify rule.")
return
}
if pass, errMsg := object.CheckAccountItemModifyRule(phoneItem, user); !pass {
c.ResponseError(errMsg)
return
}
phonePrefix := "86"
if org != nil && org.PhonePrefix != "" {
phonePrefix = org.PhonePrefix
}
checkDest = fmt.Sprintf("+%s%s", phonePrefix, dest)
} else if destType == "email" {
emailItem := object.GetAccountItemByName("Email", org)
if emailItem == nil {
c.ResponseError("Unable to get the email modify rule.")
return
}
if pass, errMsg := object.CheckAccountItemModifyRule(emailItem, user); !pass {
c.ResponseError(errMsg)
return
}
}
if ret := object.CheckVerificationCode(checkDest, code); len(ret) != 0 {
c.ResponseError(ret)

150
controllers/webauthn.go Normal file
View File

@ -0,0 +1,150 @@
// 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 controllers
import (
"bytes"
"fmt"
"io"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/webauthn"
)
// WebAuthnSignupBegin
// @Title WebAuthnSignupBegin
// @Tag User API
// @Description WebAuthn Registration Flow 1st stage
// @Success 200 {object} protocol.CredentialCreation The CredentialCreationOptions object
// @router /webauthn/signup/begin [get]
func (c *ApiController) WebAuthnSignupBegin() {
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
user := c.getCurrentUser()
if user == nil {
c.ResponseError("Please login first.")
return
}
registerOptions := func(credCreationOpts *protocol.PublicKeyCredentialCreationOptions) {
credCreationOpts.CredentialExcludeList = user.CredentialExcludeList()
}
options, sessionData, err := webauthnObj.BeginRegistration(
user,
registerOptions,
)
if err != nil {
c.ResponseError(err.Error())
return
}
c.SetSession("registration", *sessionData)
c.Data["json"] = options
c.ServeJSON()
}
// WebAuthnSignupFinish
// @Title WebAuthnSignupFinish
// @Tag User API
// @Description WebAuthn Registration Flow 2nd stage
// @Param body body protocol.CredentialCreationResponse true "authenticator attestation Response"
// @Success 200 {object} Response "The Response object"
// @router /webauthn/signup/finish [post]
func (c *ApiController) WebAuthnSignupFinish() {
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
user := c.getCurrentUser()
if user == nil {
c.ResponseError("Please login first.")
return
}
sessionObj := c.GetSession("registration")
sessionData, ok := sessionObj.(webauthn.SessionData)
if !ok {
c.ResponseError("Please call WebAuthnSignupBegin first")
return
}
c.Ctx.Request.Body = io.NopCloser(bytes.NewBuffer(c.Ctx.Input.RequestBody))
credential, err := webauthnObj.FinishRegistration(user, sessionData, c.Ctx.Request)
if err != nil {
c.ResponseError(err.Error())
return
}
isGlobalAdmin := c.IsGlobalAdmin()
user.AddCredentials(*credential, isGlobalAdmin)
c.ResponseOk()
}
// WebAuthnSigninBegin
// @Title WebAuthnSigninBegin
// @Tag Login API
// @Description WebAuthn Login Flow 1st stage
// @Param owner query string true "owner"
// @Param name query string true "name"
// @Success 200 {object} protocol.CredentialAssertion The CredentialAssertion object
// @router /webauthn/signin/begin [get]
func (c *ApiController) WebAuthnSigninBegin() {
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
userOwner := c.Input().Get("owner")
userName := c.Input().Get("name")
user := object.GetUserByFields(userOwner, userName)
if user == nil {
c.ResponseError(fmt.Sprintf("The user: %s/%s doesn't exist", userOwner, userName))
return
}
options, sessionData, err := webauthnObj.BeginLogin(user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.SetSession("authentication", *sessionData)
c.Data["json"] = options
c.ServeJSON()
}
// WebAuthnSigninFinish
// @Title WebAuthnSigninBegin
// @Tag Login API
// @Description WebAuthn Login Flow 2nd stage
// @Param body body protocol.CredentialAssertionResponse true "authenticator assertion Response"
// @Success 200 {object} Response "The Response object"
// @router /webauthn/signin/finish [post]
func (c *ApiController) WebAuthnSigninFinish() {
responseType := c.Input().Get("responseType")
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
sessionObj := c.GetSession("authentication")
sessionData, ok := sessionObj.(webauthn.SessionData)
if !ok {
c.ResponseError("Please call WebAuthnSigninBegin first")
return
}
c.Ctx.Request.Body = io.NopCloser(bytes.NewBuffer(c.Ctx.Input.RequestBody))
userId := string(sessionData.UserID)
user := object.GetUser(userId)
_, err := webauthnObj.FinishLogin(user, sessionData, c.Ctx.Request)
if err != nil {
c.ResponseError(err.Error())
return
}
c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
application := object.GetApplicationByUser(user)
var form RequestForm
form.Type = responseType
resp := c.HandleLoggedIn(application, user, &form)
c.Data["json"] = resp
c.ServeJSON()
}

View File

@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/astaxie/beego/utils/pagination"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -48,6 +48,7 @@ func (c *ApiController) GetWebhooks() {
}
}
// GetWebhook
// @Title GetWebhook
// @Tag Webhook API
// @Description get webhook
@ -61,6 +62,7 @@ func (c *ApiController) GetWebhook() {
c.ServeJSON()
}
// UpdateWebhook
// @Title UpdateWebhook
// @Tag Webhook API
// @Description update webhook
@ -74,13 +76,15 @@ func (c *ApiController) UpdateWebhook() {
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook))
c.ServeJSON()
}
// AddWebhook
// @Title AddWebhook
// @Tag Webhook API
// @Description add webhook
@ -91,13 +95,15 @@ func (c *ApiController) AddWebhook() {
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddWebhook(&webhook))
c.ServeJSON()
}
// DeleteWebhook
// @Title DeleteWebhook
// @Tag Webhook API
// @Description delete webhook
@ -108,7 +114,8 @@ func (c *ApiController) DeleteWebhook() {
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteWebhook(&webhook))

View File

@ -24,7 +24,6 @@ func NewArgon2idCredManager() *Argon2idCredManager {
}
func (cm *Argon2idCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
hash, err := argon2id.CreateHash(password, argon2id.DefaultParams)
if err != nil {
return ""

View File

@ -17,6 +17,7 @@ package cred
import (
"crypto/sha256"
"encoding/base64"
"golang.org/x/crypto/pbkdf2"
)
@ -36,4 +37,4 @@ func (cm *Pbkdf2SaltCredManager) GetHashedPassword(password string, userSalt str
func (cm *Pbkdf2SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, userSalt, organizationSalt)
}
}

70
deployment/deploy.go Normal file
View File

@ -0,0 +1,70 @@
// 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 deployment
import (
"fmt"
"os"
"strings"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/storage"
"github.com/casdoor/casdoor/util"
"github.com/casdoor/oss"
)
func deployStaticFiles(provider *object.Provider) {
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
if storageProvider == nil {
panic(fmt.Sprintf("the provider type: %s is not supported", provider.Type))
}
uploadFolder(storageProvider, "js")
uploadFolder(storageProvider, "css")
updateHtml(provider.Domain)
}
func uploadFolder(storageProvider oss.StorageInterface, folder string) {
path := fmt.Sprintf("../web/build/static/%s/", folder)
filenames := util.ListFiles(path)
for _, filename := range filenames {
if !strings.HasSuffix(filename, folder) {
continue
}
file, err := os.Open(path + filename)
if err != nil {
panic(err)
}
objectKey := fmt.Sprintf("static/%s/%s", folder, filename)
_, err = storageProvider.Put(objectKey, file)
if err != nil {
panic(err)
}
fmt.Printf("Uploaded [%s] to [%s]\n", path, objectKey)
}
}
func updateHtml(domainPath string) {
htmlPath := "../web/build/index.html"
html := util.ReadStringFromPath(htmlPath)
html = strings.Replace(html, "\"/static/", fmt.Sprintf("\"%s", domainPath), -1)
util.WriteStringToPath(html, htmlPath)
fmt.Printf("Updated HTML to [%s]\n", html)
}

29
deployment/deploy_test.go Normal file
View File

@ -0,0 +1,29 @@
// 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.
//go:build !skipCi
// +build !skipCi
package deployment
import (
"testing"
"github.com/casdoor/casdoor/object"
)
func TestDeployStaticFiles(t *testing.T) {
provider := object.GetProvider("admin/provider_storage_aliyun_oss")
deployStaticFiles(provider)
}

View File

@ -1,7 +1,8 @@
#!/bin/bash
if [ "${MYSQL_ROOT_PASSWORD}" = "" ] ;then MYSQL_ROOT_PASSWORD=123456 ;fi
service mariadb start
mysqladmin -u root password ${MYSQL_ROOT_PASSWORD}
exec /app/server --createDatabase=true
exec /server --createDatabase=true

20
go.mod
View File

@ -5,36 +5,46 @@ go 1.16
require (
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/astaxie/beego v1.12.3
github.com/aws/aws-sdk-go v1.44.4
github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.30.1
github.com/casbin/xorm-adapter/v2 v2.5.1
github.com/casdoor/go-sms-sender v0.2.0
github.com/casdoor/goth v1.69.0-FIX1
github.com/casbin/xorm-adapter/v3 v3.0.1
github.com/casdoor/go-sms-sender v0.5.1
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/forestmgy/ldapserver v1.1.0
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/google/go-cmp v0.5.8 // indirect
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/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
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
github.com/russellhaering/gosaml2 v0.6.0
github.com/russellhaering/goxmldsig v1.1.1
github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.8.0
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/ini.v1 v1.62.0 // indirect

90
go.sum
View File

@ -74,13 +74,13 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0q
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beego/beego v1.12.11 h1:MWKcnpavb7iAIS0m6uuEq6pHKkYvGNw/5umIUKqL7jM=
github.com/beego/beego v1.12.11/go.mod h1:QURFL1HldOcCZAxnc1cZ7wrplsYR5dKPHFjmk6WkLAs=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
@ -96,12 +96,12 @@ github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/xorm-adapter/v2 v2.5.1 h1:BkpIxRHKa0s3bSMx173PpuU7oTs+Zw7XmD0BIta0HGM=
github.com/casbin/xorm-adapter/v2 v2.5.1/go.mod h1:AeH4dBKHC9/zYxzdPVHhPDzF8LYLqjDdb767CWJoV54=
github.com/casdoor/go-sms-sender v0.2.0 h1:52bin4EBOPzOee64s9UK7jxd22FODvT9/+Y/Z+PSHpg=
github.com/casdoor/go-sms-sender v0.2.0/go.mod h1:fsZsNnALvFIo+HFcE1U/oCQv4ZT42FdglXKMsEm3WSk=
github.com/casdoor/goth v1.69.0-FIX1 h1:24Y3tfaJxWGJbxickGe3F9y2c8X1PgsQynhxGXV1f9Q=
github.com/casdoor/goth v1.69.0-FIX1/go.mod h1:Om55nRo8CkeDkPSNBbzXW4G5uI28ZUkSk5S69dPek3s=
github.com/casbin/xorm-adapter/v3 v3.0.1 h1:0l0zkYxo6cNuIdrBZgFxlje1TRvmheYa/zIp+sGPK58=
github.com/casbin/xorm-adapter/v3 v3.0.1/go.mod h1:1BL7rHEDXrxO+vQdSo/ZaWKRivXl7YTos67GdMYcd20=
github.com/casdoor/go-sms-sender v0.5.1 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0=
github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI=
github.com/casdoor/goth v1.69.0-FIX2 h1:RgfIMkL9kekylgxHHK2ZY8ASAwOGns2HVlaBwLu7Bcs=
github.com/casdoor/goth v1.69.0-FIX2/go.mod h1:Om55nRo8CkeDkPSNBbzXW4G5uI28ZUkSk5S69dPek3s=
github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -111,11 +111,13 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig=
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/go-couchbase v0.0.0-20201216133707-c04035124b17/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=
github.com/couchbase/gomemcached v0.1.2-0.20201224031647-c432ccf49f32/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo=
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -123,7 +125,10 @@ 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=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
@ -132,9 +137,13 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/forestmgy/ldapserver v1.1.0 h1:gvil4nuLhqPEL8SugCkFhRyA0/lIvRdwZSqlrw63ll4=
github.com/forestmgy/ldapserver v1.1.0/go.mod h1:1RZ8lox1QSY7rmbjdmy+sYQXY4Lp7SpGzpdE3+j3IyM=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ=
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
@ -149,6 +158,8 @@ github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
github.com/go-pay/gopay v1.5.72/go.mod h1:0qOGIJuFW7PKDOjmecwKyW0mgsVImgwB9yPJj0ilpn8=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -164,8 +175,12 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
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=
@ -177,8 +192,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -201,6 +217,8 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -208,8 +226,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -286,6 +305,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 h1:wIONC+HMNRqmWBjuMxhatuSzHaljStc4gjDeKycxy0A=
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 h1:erppMjjp69Rertg1zlgRbLJH1u+eCmRPxKjMZ5I8/Ro=
@ -298,6 +319,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -318,7 +341,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -363,6 +385,8 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
@ -376,15 +400,17 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
@ -393,15 +419,26 @@ github.com/tencentcloud/tencentcloud-sdk-go v1.0.154 h1:THBgwGwUQtsw6L53cSSA2wwL
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/twilio/twilio-go v0.26.0 h1:wFW4oTe3/LKt6bvByP7eio8JsjtaLHjMQKOUEzQry7U=
github.com/twilio/twilio-go v0.26.0/go.mod h1:lz62Hopu4vicpQ056H5TJ0JE4AP0rS3sQ35/ejmgOwE=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA=
github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@ -413,11 +450,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@ -453,6 +492,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -487,6 +527,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
@ -508,6 +549,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -521,7 +563,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -543,12 +587,17 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -607,10 +656,10 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -723,8 +772,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -39,6 +39,7 @@ func readI18nFile(language string) *I18nData {
func writeI18nFile(language string, data *I18nData) {
s := util.StructToJsonFormatted(data)
s = strings.ReplaceAll(s, "\\u0026", "&")
s += "\n"
println(s)
util.WriteStringToPath(s, getI18nFilePath(language))

View File

@ -19,7 +19,7 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"time"
@ -59,12 +59,12 @@ func (idp *AdfsIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *AdfsIdProvider) getConfig(hostUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
AuthURL: fmt.Sprintf("%s/adfs/oauth2/authorize", hostUrl),
TokenURL: fmt.Sprintf("%s/adfs/oauth2/token", hostUrl),
}
var config = &oauth2.Config{
config := &oauth2.Config{
Endpoint: endpoint,
}
@ -77,6 +77,7 @@ type AdfsToken struct {
ErrMsg string `json:"error_description"`
}
// GetToken
// get more detail via: https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/overview/ad-fs-openid-connect-oauth-flows-scenarios#request-an-access-token
func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
payload := url.Values{}
@ -88,7 +89,7 @@ func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -109,6 +110,7 @@ func (idp *AdfsIdProvider) GetToken(code string) (*oauth2.Token, error) {
return token, nil
}
// GetUserInfo
// Since the userinfo endpoint of ADFS only returns sub,
// the id_token is used to resolve the userinfo
func (idp *AdfsIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
@ -122,10 +124,10 @@ func (idp *AdfsIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
}
tokenSrc := []byte(token.AccessToken)
publicKey, _ := keyset.Keys[0].Materialize()
id_token, _ := jwt.Parse(bytes.NewReader(tokenSrc), jwt.WithVerify(jwa.RS256, publicKey))
sid, _ := id_token.Get("sid")
upn, _ := id_token.Get("upn")
name, _ := id_token.Get("unique_name")
idToken, _ := jwt.Parse(bytes.NewReader(tokenSrc), jwt.WithVerify(jwa.RS256, publicKey))
sid, _ := idToken.Get("sid")
upn, _ := idToken.Get("upn")
name, _ := idToken.Get("unique_name")
userinfo := &UserInfo{
Id: sid.(string),
Username: name.(string),

View File

@ -24,7 +24,6 @@ import (
"encoding/json"
"encoding/pem"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
@ -56,12 +55,12 @@ func (idp *AlipayIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *AlipayIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
AuthURL: "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm",
TokenURL: "https://openapi.alipay.com/gateway.do",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"", ""},
Endpoint: endpoint,
ClientID: clientId,
@ -205,8 +204,7 @@ func (idp *AlipayIdProvider) postWithBody(body interface{}, targetUrl string) ([
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,7 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"golang.org/x/oauth2"
@ -46,12 +46,12 @@ func (idp *BaiduIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *BaiduIdProvider) getConfig() *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
AuthURL: "https://openapi.baidu.com/oauth/2.0/authorize",
TokenURL: "https://openapi.baidu.com/oauth/2.0/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"email"},
Endpoint: endpoint,
}
@ -97,7 +97,7 @@ func (idp *BaiduIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
@ -47,12 +46,12 @@ func (idp *BilibiliIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *BilibiliIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://api.bilibili.com/x/account-oauth2/v1/token",
AuthURL: "http://member.bilibili.com/arcopen/fn/user/account/info",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"", ""},
Endpoint: endpoint,
ClientID: clientId,
@ -76,6 +75,7 @@ type BilibiliIdProviderTokenResponse struct {
Data BilibiliProviderToken `json:"data"`
}
// GetToken
/*
{
"code": 0,
@ -104,7 +104,6 @@ func (idp *BilibiliIdProvider) GetToken(code string) (*oauth2.Token, error) {
}
data, err := idp.postWithBody(pTokenParams, idp.Config.Endpoint.TokenURL)
if err != nil {
return nil, err
}
@ -144,7 +143,7 @@ func (idp *BilibiliIdProvider) GetToken(code string) (*oauth2.Token, error) {
type BilibiliUserInfo struct {
Name string `json:"name"`
Face string `json:"face"`
OpenId string `json:"openid`
OpenId string `json:"openid"`
}
type BilibiliUserInfoResponse struct {
@ -167,12 +166,11 @@ func (idp *BilibiliIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
userInfoUrl := fmt.Sprintf("%s?%s", idp.Config.Endpoint.AuthURL, params.Encode())
resp, err := idp.Client.Get(userInfoUrl)
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -206,7 +204,7 @@ func (idp *BilibiliIdProvider) postWithBody(body interface{}, url string) ([]byt
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -17,7 +17,7 @@ package idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"time"
@ -71,8 +71,7 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -82,7 +81,7 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
return nil, err
}
//check if token is expired
// check if token is expired
if pToken.ExpiresIn <= 0 {
return nil, fmt.Errorf("%s", pToken.AccessToken)
}
@ -91,7 +90,6 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
Expiry: time.Unix(time.Now().Unix()+int64(pToken.ExpiresIn), 0),
}
return token, nil
}
/*
@ -125,7 +123,7 @@ func (idp *CasdoorIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error
if err != nil {
return nil, err
}
//add accesstoken to bearer token
// add accesstoken to bearer token
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
resp, err := idp.Client.Do(request)
if err != nil {
@ -133,7 +131,7 @@ func (idp *CasdoorIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -155,5 +153,4 @@ func (idp *CasdoorIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error
AvatarUrl: cdUserinfo.AvatarUrl,
}
return userInfo, nil
}

View File

@ -18,7 +18,7 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
_ "net/url"
_ "time"
@ -36,7 +36,7 @@ func NewCustomIdProvider(clientId string, clientSecret string, redirectUrl strin
idp := &CustomIdProvider{}
idp.UserInfoUrl = userInfoUrl
var config = &oauth2.Config{
config := &oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUrl,
@ -76,7 +76,7 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
if err != nil {
return nil, err
}
//add accessToken to request header
// add accessToken to request header
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
resp, err := idp.Client.Do(request)
if err != nil {
@ -84,7 +84,7 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
@ -48,12 +47,12 @@ func (idp *DingTalkIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *DingTalkIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
AuthURL: "https://api.dingtalk.com/v1.0/contact/users/me",
TokenURL: "https://api.dingtalk.com/v1.0/oauth2/userAccessToken",
}
var config = &oauth2.Config{
config := &oauth2.Config{
// DingTalk not allow to set scopes,here it is just a placeholder,
// convenient to use later
Scopes: []string{"", ""},
@ -101,7 +100,7 @@ func (idp *DingTalkIdProvider) GetToken(code string) (*oauth2.Token, error) {
token := &oauth2.Token{
AccessToken: pToken.AccessToken,
Expiry: time.Unix(time.Now().Unix()+int64(pToken.ExpiresIn), 0),
Expiry: time.Unix(time.Now().Unix()+pToken.ExpiresIn, 0),
}
return token, nil
}
@ -122,6 +121,7 @@ func (idp *DingTalkIdProvider) GetToken(code string) (*oauth2.Token, error) {
type DingTalkUserResponse struct {
Nick string `json:"nick"`
OpenId string `json:"openId"`
UnionId string `json:"unionId"`
AvatarUrl string `json:"avatarUrl"`
Email string `json:"email"`
Errmsg string `json:"message"`
@ -145,7 +145,7 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -163,6 +163,7 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
Id: dtUserInfo.OpenId,
Username: dtUserInfo.Nick,
DisplayName: dtUserInfo.Nick,
UnionId: dtUserInfo.UnionId,
Email: dtUserInfo.Email,
AvatarUrl: dtUserInfo.AvatarUrl,
}
@ -180,7 +181,7 @@ func (idp *DingTalkIdProvider) postWithBody(body interface{}, url string) ([]byt
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"time"
@ -42,12 +42,12 @@ func (idp *DouyinIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *DouyinIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://open.douyin.com/oauth/access_token",
AuthURL: "https://open.douyin.com/platform/oauth/connect",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"user_info"},
Endpoint: endpoint,
ClientID: clientId,
@ -98,7 +98,7 @@ func (idp *DouyinIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -177,7 +177,7 @@ func (idp *DouyinIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -46,11 +46,11 @@ func (idp *FacebookIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *FacebookIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://graph.facebook.com/oauth/access_token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"email,public_profile"},
Endpoint: endpoint,
ClientID: clientId,
@ -62,15 +62,16 @@ func (idp *FacebookIdProvider) getConfig(clientId string, clientSecret string, r
}
type FacebookAccessToken struct {
AccessToken string `json:"access_token"` //Interface call credentials
TokenType string `json:"token_type"` //Access token type
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
AccessToken string `json:"access_token"` // Interface call credentials
TokenType string `json:"token_type"` // Access token type
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
}
type FacebookCheckToken struct {
Data string `json:"data"`
}
// FacebookCheckTokenData
// Get more detail via: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken
type FacebookCheckTokenData struct {
UserId string `json:"user_id"`

View File

@ -19,7 +19,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
@ -49,11 +48,11 @@ func (idp *GiteeIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *GiteeIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://gitee.com/oauth/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"user_info emails"},
Endpoint: endpoint,
@ -93,7 +92,7 @@ func (idp *GiteeIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil {
return nil, err
}
rbs, err := ioutil.ReadAll(resp.Body)
rbs, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strconv"
"strings"
@ -49,12 +48,12 @@ func (idp *GithubIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *GithubIdProvider) getConfig() *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
AuthURL: "https://github.com/login/oauth/authorize",
TokenURL: "https://github.com/login/oauth/access_token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"user:email", "read:user"},
Endpoint: endpoint,
}
@ -93,7 +92,6 @@ func (idp *GithubIdProvider) GetToken(code string) (*oauth2.Token, error) {
}
return token, nil
}
//{
@ -203,7 +201,7 @@ func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -237,7 +235,7 @@ func (idp *GithubIdProvider) postWithBody(body interface{}, url string) ([]byte,
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -17,7 +17,7 @@ package idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"strconv"
@ -46,11 +46,11 @@ func (idp *GitlabIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *GitlabIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://gitlab.com/oauth/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"read_user+profile"},
Endpoint: endpoint,
ClientID: clientId,
@ -85,7 +85,7 @@ func (idp *GitlabIdProvider) GetToken(code string) (*oauth2.Token, error) {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -209,7 +209,7 @@ func (idp *GitlabIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -19,7 +19,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"golang.org/x/oauth2"
@ -47,12 +47,12 @@ func (idp *GoogleIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *GoogleIdProvider) getConfig() *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"profile", "email"},
Endpoint: endpoint,
}
@ -95,7 +95,7 @@ func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -207,7 +207,8 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
return &idp
}
//Goth's idp all implement the Client method, but since the goth.Provider interface does not provide to modify idp's client method, reflection is required
// SetHttpClient
// Goth's idp all implement the Client method, but since the goth.Provider interface does not provide to modify idp's client method, reflection is required
func (idp *GothIdProvider) SetHttpClient(client *http.Client) {
idpClient := reflect.ValueOf(idp.Provider).Elem().FieldByName("HTTPClient")
idpClient.Set(reflect.ValueOf(client))
@ -225,8 +226,8 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
return nil, err
}
} else {
//Need to construct variables supported by goth
//to call the function to obtain accessToken
// Need to construct variables supported by goth
// to call the function to obtain accessToken
value = url.Values{}
value.Add("code", code)
}
@ -235,7 +236,7 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
return nil, err
}
//Get ExpiresAt's value
// Get ExpiresAt's value
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
if valueOfExpire.IsValid() {
expireAt = valueOfExpire.Interface().(time.Time)
@ -264,8 +265,8 @@ func getUser(gothUser goth.User, provider string) *UserInfo {
Email: gothUser.Email,
AvatarUrl: gothUser.AvatarURL,
}
//Some idp return an empty Name
//so construct the Name with firstname and lastname or nickname
// Some idp return an empty Name
// so construct the Name with firstname and lastname or nickname
if user.Username == "" {
if gothUser.FirstName != "" && gothUser.LastName != "" {
user.Username = getName(gothUser.FirstName, gothUser.LastName)
@ -281,7 +282,7 @@ func getUser(gothUser goth.User, provider string) *UserInfo {
}
}
if provider == "steam" {
user.Username = user.DisplayName
user.Username = user.Id
user.Email = ""
}
return &user

View File

@ -17,7 +17,7 @@ package idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"golang.org/x/oauth2"
@ -43,7 +43,7 @@ func (idp *InfoflowInternalIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *InfoflowInternalIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var config = &oauth2.Config{
config := &oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUrl,
@ -58,6 +58,7 @@ type InfoflowInterToken struct {
AccessToken string `json:"access_token"`
}
// GetToken
// get more detail via: https://qy.baidu.com/doc/index.html#/inner_quickstart/flow?id=%E8%8E%B7%E5%8F%96accesstoken
func (idp *InfoflowInternalIdProvider) GetToken(code string) (*oauth2.Token, error) {
pTokenParams := &struct {
@ -69,7 +70,7 @@ func (idp *InfoflowInternalIdProvider) GetToken(code string) (*oauth2.Token, err
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -137,9 +138,10 @@ type InfoflowInternalUserInfo struct {
Email string `json:"email"`
}
// GetUserInfo
// get more detail via: https://qy.baidu.com/doc/index.html#/inner_serverapi/contacts?id=%e8%8e%b7%e5%8f%96%e6%88%90%e5%91%98
func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
//Get userid first
// Get userid first
accessToken := token.AccessToken
code := token.Extra("code").(string)
resp, err := idp.Client.Get(fmt.Sprintf("https://qy.im.baidu.com/api/user/getuserinfo?access_token=%s&code=%s&agentid=%s", accessToken, code, idp.AgentId))
@ -147,7 +149,7 @@ func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserIn
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -159,13 +161,13 @@ func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserIn
if userResp.Errcode != 0 {
return nil, fmt.Errorf("userIdResp.Errcode = %d, userIdResp.Errmsg = %s", userResp.Errcode, userResp.Errmsg)
}
//Use userid and accesstoken to get user information
// Use userid and accesstoken to get user information
resp, err = idp.Client.Get(fmt.Sprintf("https://api.im.baidu.com/api/user/get?access_token=%s&userid=%s", accessToken, userResp.UserId))
if err != nil {
return nil, err
}
data, err = ioutil.ReadAll(resp.Body)
data, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
@ -47,7 +46,7 @@ func (idp *InfoflowIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *InfoflowIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var config = &oauth2.Config{
config := &oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUrl,
@ -63,6 +62,7 @@ type InfoflowToken struct {
ExpiresIn int `json:"expires_in"`
}
// GetToken
// get more detail via: https://qy.baidu.com/doc/index.html#/third_serverapi/authority
func (idp *InfoflowIdProvider) GetToken(code string) (*oauth2.Token, error) {
pTokenParams := &struct {
@ -134,9 +134,10 @@ type InfoflowUserInfo struct {
Email string `json:"email"`
}
// GetUserInfo
// get more detail via: https://qy.baidu.com/doc/index.html#/third_serverapi/contacts?id=%e8%8e%b7%e5%8f%96%e6%88%90%e5%91%98
func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
//Get userid first
// Get userid first
accessToken := token.AccessToken
code := token.Extra("code").(string)
resp, err := idp.Client.Get(fmt.Sprintf("https://api.im.baidu.com/api/user/getuserinfo?access_token=%s&code=%s&agentid=%s", accessToken, code, idp.AgentId))
@ -144,7 +145,7 @@ func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -156,13 +157,13 @@ func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
if userResp.Errcode != 0 {
return nil, fmt.Errorf("userIdResp.Errcode = %d, userIdResp.Errmsg = %s", userResp.Errcode, userResp.Errmsg)
}
//Use userid and accesstoken to get user information
// Use userid and accesstoken to get user information
resp, err = idp.Client.Get(fmt.Sprintf("https://api.im.baidu.com/api/user/get?access_token=%s&userid=%s", accessToken, userResp.UserId))
if err != nil {
return nil, err
}
data, err = ioutil.ReadAll(resp.Body)
data, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -197,7 +198,7 @@ func (idp *InfoflowIdProvider) postWithBody(body interface{}, url string) ([]byt
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -17,7 +17,6 @@ package idp
import (
"encoding/json"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
@ -45,11 +44,11 @@ func (idp *LarkIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *LarkIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{},
Endpoint: endpoint,
ClientID: clientId,
@ -173,7 +172,7 @@ func (idp *LarkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
return nil, err
}
defer resp.Body.Close()
data, err = ioutil.ReadAll(resp.Body)
data, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -204,7 +203,7 @@ func (idp *LarkIdProvider) postWithBody(body interface{}, url string) ([]byte, e
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
@ -47,11 +46,11 @@ func (idp *LinkedInIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *LinkedInIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://www.linkedIn.com/oauth/v2/accessToken",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"email,public_profile"},
Endpoint: endpoint,
ClientID: clientId,
@ -63,8 +62,8 @@ func (idp *LinkedInIdProvider) getConfig(clientId string, clientSecret string, r
}
type LinkedInAccessToken struct {
AccessToken string `json:"access_token"` //Interface call credentials
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
AccessToken string `json:"access_token"` // Interface call credentials
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
}
// GetToken use code get access_token (*operation of getting code ought to be done in front)
@ -85,7 +84,7 @@ func (idp *LinkedInIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil {
return nil, err
}
rbs, err := ioutil.ReadAll(resp.Body)
rbs, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -323,7 +322,7 @@ func (idp *LinkedInIdProvider) GetUrlRespWithAuthorization(url, token string) ([
}
}(resp.Body)
bs, err := ioutil.ReadAll(resp.Body)
bs, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -17,7 +17,7 @@ package idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"time"
@ -48,12 +48,12 @@ func (idp *OktaIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *OktaIdProvider) getConfig(hostUrl string, clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: fmt.Sprintf("%s/v1/token", hostUrl),
AuthURL: fmt.Sprintf("%s/v1/authorize", hostUrl),
}
var config = &oauth2.Config{
config := &oauth2.Config{
// openid is required for authentication requests
// get more details via: https://developer.okta.com/docs/reference/api/oidc/#reserved-scopes
Scopes: []string{"openid", "profile", "email"},
@ -114,7 +114,7 @@ func (idp *OktaIdProvider) GetToken(code string) (*oauth2.Token, error) {
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -178,7 +178,7 @@ func (idp *OktaIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -25,6 +25,7 @@ type UserInfo struct {
Id string
Username string
DisplayName string
UnionId string
Email string
AvatarUrl string
}

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"regexp"
@ -48,11 +48,11 @@ func (idp *QqIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *QqIdProvider) getConfig() *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://graph.qq.com/oauth2.0/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"get_user_info"},
Endpoint: endpoint,
}
@ -75,7 +75,7 @@ func (idp *QqIdProvider) GetToken(code string) (*oauth2.Token, error) {
}
defer resp.Body.Close()
tokenContent, err := ioutil.ReadAll(resp.Body)
tokenContent, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -148,7 +148,7 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
}
defer resp.Body.Close()
openIdBody, err := ioutil.ReadAll(resp.Body)
openIdBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -167,7 +167,7 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
}
defer resp.Body.Close()
userInfoBody, err := ioutil.ReadAll(resp.Body)
userInfoBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -47,11 +47,11 @@ func (idp *WeChatIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *WeChatIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://graph.qq.com/oauth2.0/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"snsapi_login"},
Endpoint: endpoint,
ClientID: clientId,
@ -63,12 +63,12 @@ func (idp *WeChatIdProvider) getConfig(clientId string, clientSecret string, red
}
type WechatAccessToken struct {
AccessToken string `json:"access_token"` //Interface call credentials
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
RefreshToken string `json:"refresh_token"` //User refresh access_token
Openid string `json:"openid"` //Unique ID of authorized user
Scope string `json:"scope"` //The scope of user authorization, separated by commas. (,)
Unionid string `json:"unionid"` //This field will appear if and only if the website application has been authorized by the user's UserInfo.
AccessToken string `json:"access_token"` // Interface call credentials
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
RefreshToken string `json:"refresh_token"` // User refresh access_token
Openid string `json:"openid"` // Unique ID of authorized user
Scope string `json:"scope"` // The scope of user authorization, separated by commas. (,)
Unionid string `json:"unionid"` // This field will appear if and only if the website application has been authorized by the user's UserInfo.
}
// GetToken use code get access_token (*operation of getting code ought to be done in front)
@ -144,7 +144,7 @@ type WechatUserInfo struct {
City string `json:"city"` // City filled in by general user's personal data
Province string `json:"province"` // Province filled in by ordinary user's personal information
Country string `json:"country"` // Country, such as China is CN
Headimgurl string `json:"headimgurl"` // User avatar, the last value represents the size of the square avatar (there are optional values of 0, 46, 64, 96, 132, 0 represents a 640*640 square avatar), this item is empty when the user does not have a avatar
Headimgurl string `json:"headimgurl"` // User avatar, the last value represents the size of the square avatar (there are optional values of 0, 46, 64, 96, 132, 0 represents a 640*640 square avatar), this item is empty when the user does not have an avatar
Privilege []string `json:"privilege"` // User Privilege information, json array, such as Wechat Woka user (chinaunicom)
Unionid string `json:"unionid"` // Unified user identification. For an application under a WeChat open platform account, the unionid of the same user is unique.
}

View File

@ -17,7 +17,7 @@ package idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"golang.org/x/oauth2"
@ -42,7 +42,7 @@ func (idp *WeChatMiniProgramIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *WeChatMiniProgramIdProvider) getConfig(clientId string, clientSecret string) *oauth2.Config {
var config = &oauth2.Config{
config := &oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
}
@ -65,7 +65,7 @@ func (idp *WeChatMiniProgramIdProvider) GetSessionByCode(code string) (*WeChatMi
return nil, err
}
defer sessionResponse.Body.Close()
data, err := ioutil.ReadAll(sessionResponse.Body)
data, err := io.ReadAll(sessionResponse.Body)
if err != nil {
return nil, err
}
@ -78,5 +78,4 @@ func (idp *WeChatMiniProgramIdProvider) GetSessionByCode(code string) (*WeChatMi
return nil, fmt.Errorf("err: %s", session.Errmsg)
}
return &session, nil
}

View File

@ -17,14 +17,15 @@ package idp
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"time"
"golang.org/x/oauth2"
)
//This idp is using wecom internal application api as idp
// WeComInternalIdProvider
// This idp is using wecom internal application api as idp
type WeComInternalIdProvider struct {
Client *http.Client
Config *oauth2.Config
@ -44,7 +45,7 @@ func (idp *WeComInternalIdProvider) SetHttpClient(client *http.Client) {
}
func (idp *WeComInternalIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var config = &oauth2.Config{
config := &oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUrl,
@ -72,7 +73,7 @@ func (idp *WeComInternalIdProvider) GetToken(code string) (*oauth2.Token, error)
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -115,7 +116,7 @@ type WecomInternalUserInfo struct {
}
func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
//Get userid first
// Get userid first
accessToken := token.AccessToken
code := token.Extra("code").(string)
resp, err := idp.Client.Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=%s&code=%s", accessToken, code))
@ -123,7 +124,7 @@ func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo,
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@ -138,13 +139,13 @@ func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo,
if userResp.OpenId != "" {
return nil, fmt.Errorf("not an internal user")
}
//Use userid and accesstoken to get user information
// Use userid and accesstoken to get user information
resp, err = idp.Client.Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s", accessToken, userResp.UserId))
if err != nil {
return nil, err
}
data, err = ioutil.ReadAll(resp.Body)
data, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
@ -46,11 +45,11 @@ func (idp *WeComIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *WeComIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://graph.qq.com/oauth2.0/token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{"snsapi_login"},
Endpoint: endpoint,
ClientID: clientId,
@ -195,7 +194,7 @@ func (idp *WeComIdProvider) postWithBody(body interface{}, url string) ([]byte,
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@ -19,7 +19,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
@ -48,11 +47,11 @@ func (idp *WeiBoIdProvider) SetHttpClient(client *http.Client) {
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
func (idp *WeiBoIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
var endpoint = oauth2.Endpoint{
endpoint := oauth2.Endpoint{
TokenURL: "https://api.weibo.com/oauth2/access_token",
}
var config = &oauth2.Config{
config := &oauth2.Config{
Scopes: []string{""},
Endpoint: endpoint,
ClientID: clientId,
@ -92,7 +91,7 @@ func (idp *WeiBoIdProvider) GetToken(code string) (*oauth2.Token, error) {
return
}
}(resp.Body)
bs, err := ioutil.ReadAll(resp.Body)
bs, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

160
init_data.json.template Normal file
View File

@ -0,0 +1,160 @@
{
"organizations": [
{
"owner": "",
"name": "",
"displayName": "",
"websiteUrl": "",
"favicon": "",
"passwordType": "",
"phonePrefix": "",
"defaultAvatar": "",
"tags": [""]
}
],
"applications": [
{
"owner": "",
"name": "",
"displayName": "",
"logo": "",
"homepageUrl": "",
"organization": "",
"cert": "",
"enablePassword": true,
"enableSignUp": true,
"clientId": "",
"clientSecret": "",
"providers": [
{
"name": "",
"canSignUp": true,
"canSignIn": true,
"canUnlink": false,
"prompted": false,
"alertType": "None"
}
],
"signupItems": [
{
"name": "ID",
"visible": false,
"required": true,
"prompted": false,
"rule": "Random"
},
{
"name": "Username",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
},
{
"name": "Display name",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
},
{
"name": "Password",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
},
{
"name": "Confirm password",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
},
{
"name": "Email",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
},
{
"name": "Phone",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
},
{
"name": "Agreement",
"visible": true,
"required": true,
"prompted": false,
"rule": "None"
}
],
"redirectUris": [""],
"expireInHours": 168
}
],
"users": [
{
"owner": "",
"name": "",
"type": "normal-user",
"password": "",
"displayName": "",
"avatar": "",
"email": "",
"phone": "",
"address": [],
"affiliation": "",
"tag": "",
"score": 2000,
"ranking": 1,
"isAdmin": true,
"isGlobalAdmin": true,
"isForbidden": false,
"isDeleted": false,
"signupApplication": "",
"createdIp": ""
}
],
"providers": [
{
"owner": "",
"name": "",
"displayName": "",
"category": "",
"type": ""
}
],
"certs": [
{
"owner": "",
"name": "",
"displayName": "",
"scope": "JWT",
"type": "x509",
"cryptoAlgorithm": "RS256",
"bitSize": 4096,
"expireInYears": 20,
"certificate": "",
"privateKey": ""
}
],
"ldaps": [
{
"id": "",
"owner": "",
"serverName": "",
"host": "",
"port": 389,
"admin": "",
"passwd": "",
"baseDn": "",
"autoSync": 0,
"lastSync": ""
}
]
}

23
main.go
View File

@ -18,11 +18,12 @@ import (
"flag"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
_ "github.com/astaxie/beego/session/redis"
"github.com/beego/beego"
"github.com/beego/beego/logs"
_ "github.com/beego/beego/session/redis"
"github.com/casdoor/casdoor/authz"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/controllers"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/routers"
@ -36,15 +37,17 @@ func main() {
object.InitAdapter(*createDatabase)
object.InitDb()
object.InitFromFile()
object.InitDefaultStorageProvider()
object.InitLdapAutoSynchronizer()
proxy.InitHttpClient()
authz.InitAuthz()
util.SafeGoroutine(func() {object.RunSyncUsersJob()})
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
// beego.DelStaticPath("/static")
// beego.SetStaticPath("/static", "web/build/static")
//beego.DelStaticPath("/static")
beego.SetStaticPath("/static", "web/build/static")
beego.BConfig.WebConfig.DirectoryIndex = true
beego.SetStaticPath("/swagger", "swagger")
beego.SetStaticPath("/files", "files")
@ -55,6 +58,7 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
beego.BConfig.WebConfig.Session.SessionOn = true
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
if conf.GetConfigString("redisEndpoint") == "" {
beego.BConfig.WebConfig.Session.SessionProvider = "file"
@ -64,14 +68,17 @@ func main() {
beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
}
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
//beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
// beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
err := logs.SetLogger("file", `{"filename":"logs/casdoor.log","maxdays":99999,"perm":"0770"}`)
if err != nil {
panic(err)
}
port := beego.AppConfig.DefaultInt("httpport", 8000)
//logs.SetLevel(logs.LevelInformational)
// logs.SetLevel(logs.LevelInformational)
logs.SetLogFuncCall(false)
go controllers.StartLdapServer()
beego.Run(fmt.Sprintf(":%v", port))
}

View File

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

View File

@ -18,12 +18,15 @@ import (
"fmt"
"runtime"
"github.com/astaxie/beego"
"github.com/beego/beego"
xormadapter "github.com/casbin/xorm-adapter/v3"
"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/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
"xorm.io/xorm/migrate"
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
"xorm.io/core"
"xorm.io/xorm"
)
@ -36,12 +39,14 @@ func InitConfig() {
panic(err)
}
beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true)
initMigrations()
}
func InitAdapter(createDatabase bool) {
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName(), conf.GetConfigString("dbName"))
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
if createDatabase {
adapter.CreateDatabase()
}
@ -143,6 +148,11 @@ func (a *Adapter) createTable() {
panic(err)
}
err = a.Engine.Sync2(new(CasbinAdapter))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(Provider))
if err != nil {
panic(err)
@ -202,6 +212,16 @@ func (a *Adapter) createTable() {
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(PermissionRule))
if err != nil {
panic(err)
}
err = a.Engine.Sync2(new(xormadapter.CasbinRule))
if err != nil {
panic(err)
}
}
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
@ -227,3 +247,22 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
}
return session
}
func initMigrations() {
migrations := []*migrate.Migration{
{
ID: "20221015CasbinRule--fill ptype field with p",
Migrate: func(tx *xorm.Engine) error {
_, err := tx.Cols("ptype").Update(&xormadapter.CasbinRule{
Ptype: "p",
})
return err
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&xormadapter.CasbinRule{})
},
},
}
m := migrate.New(adapter.Engine, migrate.DefaultOptions, migrations)
m.Migrate()
}

View File

@ -17,6 +17,7 @@ package object
import (
"fmt"
"net/url"
"regexp"
"strings"
"github.com/casdoor/casdoor/util"
@ -45,8 +46,10 @@ type Application struct {
EnablePassword bool `json:"enablePassword"`
EnableSignUp bool `json:"enableSignUp"`
EnableSigninSession bool `json:"enableSigninSession"`
EnableAutoSignin bool `json:"enableAutoSignin"`
EnableCodeSignin bool `json:"enableCodeSignin"`
EnableSamlCompress bool `json:"enableSamlCompress"`
EnableWebAuthn bool `json:"enableWebAuthn"`
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"`
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
@ -65,6 +68,9 @@ type Application struct {
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
FormCss string `xorm:"text" json:"formCss"`
FormOffset int `json:"formOffset"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
}
func GetApplicationCount(owner, field, value string) int {
@ -280,8 +286,12 @@ func UpdateApplication(id string, application *Application) bool {
}
func AddApplication(application *Application) bool {
application.ClientId = util.GenerateClientId()
application.ClientSecret = util.GenerateClientSecret()
if application.ClientId == "" {
application.ClientId = util.GenerateClientId()
}
if application.ClientSecret == "" {
application.ClientSecret = util.GenerateClientSecret()
}
for _, providerItem := range application.Providers {
providerItem.Provider = nil
}
@ -312,9 +322,10 @@ func (application *Application) GetId() string {
}
func CheckRedirectUriValid(application *Application, redirectUri string) bool {
var validUri = false
validUri := false
for _, tmpUri := range application.RedirectUris {
if strings.Contains(redirectUri, tmpUri) {
tmpUriRegex := regexp.MustCompile(tmpUri)
if tmpUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, tmpUri) {
validUri = true
break
}
@ -357,3 +368,34 @@ func IsAllowOrigin(origin string) bool {
return allowOrigin
}
func getApplicationMap(organization string) map[string]*Application {
applications := GetApplicationsByOrganizationName("admin", organization)
applicationMap := make(map[string]*Application)
for _, application := range applications {
applicationMap[application.Name] = application
}
return applicationMap
}
func ExtendManagedAccountsWithUser(user *User) *User {
if user.ManagedAccounts == nil || len(user.ManagedAccounts) == 0 {
return user
}
applicationMap := getApplicationMap(user.Owner)
var managedAccounts []ManagedAccount
for _, managedAccount := range user.ManagedAccounts {
application := applicationMap[managedAccount.Application]
if application != nil {
managedAccount.SigninUrl = application.SigninUrl
managedAccounts = append(managedAccounts, managedAccount)
}
}
user.ManagedAccounts = managedAccounts
return user
}

View File

@ -73,6 +73,10 @@ func (application *Application) IsSignupItemRequired(itemName string) bool {
return signupItem.Required
}
func (si *SignupItem) isSignupItemPrompted() bool {
return si.Visible && si.Prompted
}
func (application *Application) GetSignupItemRule(itemName string) string {
signupItem := application.getSignupItem(itemName)
if signupItem == nil {
@ -92,6 +96,16 @@ func (application *Application) getAllPromptedProviderItems() []*ProviderItem {
return res
}
func (application *Application) getAllPromptedSignupItems() []*SignupItem {
res := []*SignupItem{}
for _, signupItem := range application.SignupItems {
if signupItem.isSignupItemPrompted() {
res = append(res, signupItem)
}
}
return res
}
func (application *Application) isAffiliationPrompted() bool {
signupItem := application.getSignupItem("Affiliation")
if signupItem == nil {
@ -107,5 +121,10 @@ func (application *Application) HasPromptPage() bool {
return true
}
signupItems := application.getAllPromptedSignupItems()
if len(signupItems) != 0 {
return true
}
return application.isAffiliationPrompted()
}

View File

@ -50,7 +50,11 @@ func downloadFile(url string) (*bytes.Buffer, error) {
return fileBuffer, nil
}
func getPermanentAvatarUrl(organization string, username string, url string) string {
func getPermanentAvatarUrl(organization string, username string, url string, upload bool) string {
if url == "" {
return ""
}
if defaultStorageProvider == nil {
return ""
}
@ -58,6 +62,14 @@ func getPermanentAvatarUrl(organization string, username string, url string) str
fullFilePath := fmt.Sprintf("/avatar/%s/%s.png", organization, username)
uploadedFileUrl, _ := getUploadFileUrl(defaultStorageProvider, fullFilePath, false)
if upload {
DownloadAndUpload(url, fullFilePath)
}
return uploadedFileUrl
}
func DownloadAndUpload(url string, fullFilePath string) {
fileBuffer, err := downloadFile(url)
if err != nil {
panic(err)
@ -67,6 +79,4 @@ func getPermanentAvatarUrl(organization string, username string, url string) str
if err != nil {
panic(err)
}
return uploadedFileUrl
}

View File

@ -32,7 +32,7 @@ func TestSyncPermanentAvatars(t *testing.T) {
continue
}
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true)
updateUserColumn("permanent_avatar", user)
fmt.Printf("[%d/%d]: Update user: [%s]'s permanent avatar: %s\n", i, len(users), user.GetId(), user.PermanentAvatar)
}

217
object/casbin_adapter.go Normal file
View File

@ -0,0 +1,217 @@
// 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 object
import (
"fmt"
"strings"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
)
type CasbinAdapter struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
Organization string `xorm:"varchar(100)" json:"organization"`
Type string `xorm:"varchar(100)" json:"type"`
Model string `xorm:"varchar(100)" json:"model"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
User string `xorm:"varchar(100)" json:"user"`
Password string `xorm:"varchar(100)" json:"password"`
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
Database string `xorm:"varchar(100)" json:"database"`
Table string `xorm:"varchar(100)" json:"table"`
IsEnabled bool `json:"isEnabled"`
Adapter *xormadapter.Adapter `xorm:"-" json:"-"`
}
func GetCasbinAdapterCount(owner, field, value string) int {
session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&CasbinAdapter{})
if err != nil {
panic(err)
}
return int(count)
}
func GetCasbinAdapters(owner string) []*CasbinAdapter {
adapters := []*CasbinAdapter{}
err := adapter.Engine.Where("owner = ?", owner).Find(&adapters)
if err != nil {
panic(err)
}
return adapters
}
func GetPaginationCasbinAdapters(owner string, page, limit int, field, value, sort, order string) []*CasbinAdapter {
session := GetSession(owner, page, limit, field, value, sort, order)
adapters := []*CasbinAdapter{}
err := session.Find(&adapters)
if err != nil {
panic(err)
}
return adapters
}
func getCasbinAdapter(owner, name string) *CasbinAdapter {
if owner == "" || name == "" {
return nil
}
casbinAdapter := CasbinAdapter{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&casbinAdapter)
if err != nil {
panic(err)
}
if existed {
return &casbinAdapter
} else {
return nil
}
}
func GetCasbinAdapter(id string) *CasbinAdapter {
owner, name := util.GetOwnerAndNameFromId(id)
return getCasbinAdapter(owner, name)
}
func UpdateCasbinAdapter(id string, casbinAdapter *CasbinAdapter) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getCasbinAdapter(owner, name) == nil {
return false
}
session := adapter.Engine.ID(core.PK{owner, name}).AllCols()
if casbinAdapter.Password == "***" {
session.Omit("password")
}
affected, err := session.Update(casbinAdapter)
if err != nil {
panic(err)
}
return affected != 0
}
func AddCasbinAdapter(casbinAdapter *CasbinAdapter) bool {
affected, err := adapter.Engine.Insert(casbinAdapter)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteCasbinAdapter(casbinAdapter *CasbinAdapter) bool {
affected, err := adapter.Engine.ID(core.PK{casbinAdapter.Owner, casbinAdapter.Name}).Delete(&CasbinAdapter{})
if err != nil {
panic(err)
}
return affected != 0
}
func (casbinAdapter *CasbinAdapter) GetId() string {
return fmt.Sprintf("%s/%s", casbinAdapter.Owner, casbinAdapter.Name)
}
func (casbinAdapter *CasbinAdapter) getTable() string {
if casbinAdapter.DatabaseType == "mssql" {
return fmt.Sprintf("[%s]", casbinAdapter.Table)
} else {
return casbinAdapter.Table
}
}
func safeReturn(policy []string, i int) string {
if len(policy) > i {
return policy[i]
} else {
return ""
}
}
func matrixToCasbinRules(pType string, policies [][]string) []*xormadapter.CasbinRule {
res := []*xormadapter.CasbinRule{}
for _, policy := range policies {
line := xormadapter.CasbinRule{
Ptype: pType,
V0: safeReturn(policy, 0),
V1: safeReturn(policy, 1),
V2: safeReturn(policy, 2),
V3: safeReturn(policy, 3),
V4: safeReturn(policy, 4),
V5: safeReturn(policy, 5),
}
res = append(res, &line)
}
return res
}
func SyncPolicies(casbinAdapter *CasbinAdapter) []*xormadapter.CasbinRule {
// init Adapter
if casbinAdapter.Adapter == nil {
var dataSourceName string
if casbinAdapter.DatabaseType == "mssql" {
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port, casbinAdapter.Database)
} else if casbinAdapter.DatabaseType == "postgres" {
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port, casbinAdapter.Database)
} else {
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port)
}
if !isCloudIntranet {
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
}
casbinAdapter.Adapter, _ = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(casbinAdapter.DatabaseType, dataSourceName, casbinAdapter.Database).Engine, casbinAdapter.getTable(), "")
}
// init Model
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
m, err := model.NewModelFromString(modelObj.ModelText)
if err != nil {
panic(err)
}
// init Enforcer
enforcer, err := casbin.NewEnforcer(m, casbinAdapter.Adapter)
if err != nil {
panic(err)
}
policies := matrixToCasbinRules("p", enforcer.GetPolicy())
if strings.Contains(modelObj.ModelText, "[role_definition]") {
policies = append(policies, matrixToCasbinRules("g", enforcer.GetGroupingPolicy())...)
}
return policies
}

View File

@ -33,7 +33,7 @@ type Cert struct {
BitSize int `json:"bitSize"`
ExpireInYears int `json:"expireInYears"`
PublicKey string `xorm:"mediumtext" json:"publicKey"`
Certificate string `xorm:"mediumtext" json:"certificate"`
PrivateKey string `xorm:"mediumtext" json:"privateKey"`
AuthorityPublicKey string `xorm:"mediumtext" json:"authorityPublicKey"`
AuthorityRootPublicKey string `xorm:"mediumtext" json:"authorityRootPublicKey"`
@ -123,9 +123,9 @@ func UpdateCert(id string, cert *Cert) bool {
}
func AddCert(cert *Cert) bool {
if cert.PublicKey == "" || cert.PrivateKey == "" {
publicKey, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner)
cert.PublicKey = publicKey
if cert.Certificate == "" || cert.PrivateKey == "" {
certificate, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner)
cert.Certificate = certificate
cert.PrivateKey = privateKey
}

View File

@ -18,6 +18,8 @@ import (
"fmt"
"regexp"
"strings"
"time"
"unicode"
"github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/util"
@ -29,6 +31,11 @@ var (
reFieldWhiteList *regexp.Regexp
)
const (
SigninWrongTimesLimit = 5
LastSignWrongTimeDuration = time.Minute * 15
)
func init() {
reWhiteSpace, _ = regexp.Compile(`\s`)
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
@ -42,11 +49,30 @@ func CheckUserSignup(application *Application, organization *Organization, usern
if application.IsSignupItemVisible("Username") {
if len(username) <= 1 {
return "username must have at least 2 characters"
} else if reWhiteSpace.MatchString(username) {
}
if unicode.IsDigit(rune(username[0])) {
return "username cannot start with a digit"
}
if util.IsEmailValid(username) {
return "username cannot be an email address"
}
if reWhiteSpace.MatchString(username) {
return "username cannot contain white spaces"
} else if HasUserByField(organization.Name, "name", username) {
}
msg := CheckUsername(username)
if msg != "" {
return msg
}
if HasUserByField(organization.Name, "name", username) {
return "username already exists"
}
if HasUserByField(organization.Name, "email", email) {
return "email already exists"
}
if HasUserByField(organization.Name, "phone", phone) {
return "phone already exists"
}
}
if len(password) <= 5 {
@ -112,7 +138,32 @@ func CheckUserSignup(application *Application, organization *Organization, usern
return ""
}
func checkSigninErrorTimes(user *User) string {
if user.SigninWrongTimes >= SigninWrongTimesLimit {
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
passedTime := time.Now().UTC().Sub(lastSignWrongTime)
seconds := int(LastSignWrongTimeDuration.Seconds() - passedTime.Seconds())
// deny the login if the error times is greater than the limit and the last login time is less than the duration
if seconds > 0 {
return fmt.Sprintf("You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", seconds/60, seconds%60)
}
// reset the error times
user.SigninWrongTimes = 0
UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, user.IsGlobalAdmin)
}
return ""
}
func CheckPassword(user *User, password string) string {
// check the login error times
if msg := checkSigninErrorTimes(user); msg != "" {
return msg
}
organization := GetOrganizationByUser(user)
if organization == nil {
return "organization does not exist"
@ -122,14 +173,17 @@ func CheckPassword(user *User, password string) string {
if credManager != nil {
if organization.MasterPassword != "" {
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
resetUserSigninErrorTimes(user)
return ""
}
}
if credManager.IsPasswordCorrect(password, user.Password, user.PasswordSalt, organization.PasswordSalt) {
resetUserSigninErrorTimes(user)
return ""
}
return "password incorrect"
return recordSigninErrorInfo(user)
} else {
return fmt.Sprintf("unsupported password type: %s", organization.PasswordType)
}
@ -182,7 +236,7 @@ func CheckUserPassword(organization string, username string, password string) (*
}
if user.Ldap != "" {
//ONLY for ldap users
// ONLY for ldap users
return checkLdapUserPassword(user, password)
} else {
msg := CheckPassword(user, password)
@ -197,14 +251,18 @@ func filterField(field string) bool {
return reFieldWhiteList.MatchString(field)
}
func CheckUserPermission(requestUserId, userId string, strict bool) (bool, error) {
func CheckUserPermission(requestUserId, userId, userOwner string, strict bool) (bool, error) {
if requestUserId == "" {
return false, fmt.Errorf("please login first")
}
targetUser := GetUser(userId)
if targetUser == nil {
return false, fmt.Errorf("the user: %s doesn't exist", userId)
if userId != "" {
targetUser := GetUser(userId)
if targetUser == nil {
return false, fmt.Errorf("the user: %s doesn't exist", userId)
}
userOwner = targetUser.Owner
}
hasPermission := false
@ -219,7 +277,7 @@ func CheckUserPermission(requestUserId, userId string, strict bool) (bool, error
hasPermission = true
} else if requestUserId == userId {
hasPermission = true
} else if targetUser.Owner == requestUser.Owner {
} else if userOwner == requestUser.Owner {
if strict {
hasPermission = requestUser.IsAdmin
} else {
@ -229,4 +287,55 @@ func CheckUserPermission(requestUserId, userId string, strict bool) (bool, error
}
return hasPermission, fmt.Errorf("you don't have the permission to do this")
}
}
func CheckAccessPermission(userId string, application *Application) (bool, error) {
permissions := GetPermissions(application.Organization)
allowed := true
var err error
for _, permission := range permissions {
if !permission.IsEnabled || len(permission.Users) == 0 {
continue
}
isHit := false
for _, resource := range permission.Resources {
if application.Name == resource {
isHit = true
break
}
}
if isHit {
containsAsterisk := ContainsAsterisk(userId, permission.Users)
if containsAsterisk {
return true, err
}
enforcer := getEnforcer(permission)
allowed, err = enforcer.Enforce(userId, application.Name, "read")
break
}
}
return allowed, err
}
func CheckUsername(username string) string {
if username == "" {
return "Empty username."
} else if len(username) > 39 {
return "Username is too long (maximum is 39 characters)."
}
exclude, _ := regexp.Compile("^[\u0021-\u007E]+$")
if !exclude.MatchString(username) {
return ""
}
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
re, _ := regexp.Compile("^[a-zA-Z0-9]+((?:-[a-zA-Z0-9]+)|(?:_[a-zA-Z0-9]+))*$")
if !re.MatchString(username) {
return "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline."
}
return ""
}

View File

@ -14,7 +14,11 @@
package object
import "regexp"
import (
"fmt"
"regexp"
"time"
)
var reRealName *regexp.Regexp
@ -29,3 +33,32 @@ func init() {
func isValidRealName(s string) bool {
return reRealName.MatchString(s)
}
func resetUserSigninErrorTimes(user *User) {
// if the password is correct and wrong times is not zero, reset the error times
if user.SigninWrongTimes == 0 {
return
}
user.SigninWrongTimes = 0
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
}
func recordSigninErrorInfo(user *User) string {
// increase failed login count
user.SigninWrongTimes++
if user.SigninWrongTimes >= SigninWrongTimesLimit {
// record the latest failed login time
user.LastSigninWrongTime = time.Now().UTC().Format(time.RFC3339)
}
// update user
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
if leftChances > 0 {
return fmt.Sprintf("password is incorrect, you have %d remaining chances", leftChances)
}
// don't show the chance error message if the user has no chance left
return fmt.Sprintf("You have entered the wrong password too many times, please wait for %d minutes and try again", int(LastSignWrongTimeDuration.Minutes()))
}

View File

@ -16,10 +16,28 @@
package object
import "github.com/go-gomail/gomail"
import (
"crypto/tls"
"github.com/go-gomail/gomail"
)
func getDialer(provider *Provider) *gomail.Dialer {
dialer := &gomail.Dialer{}
if provider.Type == "SUBMAIL" {
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.AppId, provider.ClientSecret)
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
} else {
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
}
dialer.SSL = !provider.DisableSsl
return dialer
}
func SendEmail(provider *Provider, title string, content string, dest string, sender string) error {
dialer := gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
dialer := getDialer(provider)
message := gomail.NewMessage()
message.SetAddressHeader("From", provider.ClientId, sender)
@ -32,7 +50,7 @@ func SendEmail(provider *Provider, title string, content string, dest string, se
// DailSmtpServer Dail Smtp server
func DailSmtpServer(provider *Provider) error {
dialer := gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
dialer := getDialer(provider)
sender, err := dialer.Dial()
if err != nil {

View File

@ -15,20 +15,30 @@
package object
import (
"io/ioutil"
"encoding/gob"
"fmt"
"os"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/webauthn"
)
func InitDb() {
MigratePermissionRule()
existed := initBuiltInOrganization()
if !existed {
initBuiltInModel()
initBuiltInPermission()
initBuiltInProvider()
initBuiltInUser()
initBuiltInApplication()
initBuiltInCert()
initBuiltInLdap()
}
initWebAuthn()
}
func initBuiltInOrganization() bool {
@ -43,10 +53,10 @@ func initBuiltInOrganization() bool {
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Organization",
WebsiteUrl: "https://example.com",
Favicon: "https://cdn.casbin.com/static/favicon.ico",
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")),
PasswordType: "plain",
PhonePrefix: "86",
DefaultAvatar: "https://casbin.org/img/casbin.svg",
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
Tags: []string{},
AccountItems: []*AccountItem{
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
@ -66,12 +76,16 @@ func initBuiltInOrganization() bool {
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
},
}
AddOrganization(organization)
@ -92,7 +106,7 @@ func initBuiltInUser() {
Type: "normal-user",
Password: "123",
DisplayName: "Admin",
Avatar: "https://casbin.org/img/casbin.svg",
Avatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
Email: "admin@example.com",
Phone: "12345678910",
Address: []string{},
@ -122,7 +136,7 @@ func initBuiltInApplication() {
Name: "app-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Casdoor",
Logo: "https://cdn.casbin.com/logo/logo_1024x256.png",
Logo: fmt.Sprintf("%s/img/casdoor-logo_1185x256.png", conf.GetConfigString("staticBaseUrl")),
HomepageUrl: "https://casdoor.org",
Organization: "built-in",
Cert: "cert-built-in",
@ -143,6 +157,7 @@ func initBuiltInApplication() {
},
RedirectUris: []string{},
ExpireInHours: 168,
FormOffset: 8,
}
AddApplication(application)
}
@ -150,11 +165,11 @@ func initBuiltInApplication() {
func readTokenFromFile() (string, string) {
pemPath := "./object/token_jwt_key.pem"
keyPath := "./object/token_jwt_key.key"
pem, err := ioutil.ReadFile(pemPath)
pem, err := os.ReadFile(pemPath)
if err != nil {
return "", ""
}
key, err := ioutil.ReadFile(keyPath)
key, err := os.ReadFile(keyPath)
if err != nil {
return "", ""
}
@ -162,7 +177,7 @@ func readTokenFromFile() (string, string) {
}
func initBuiltInCert() {
tokenJwtPublicKey, tokenJwtPrivateKey := readTokenFromFile()
tokenJwtCertificate, tokenJwtPrivateKey := readTokenFromFile()
cert := getCert("admin", "cert-built-in")
if cert != nil {
return
@ -178,7 +193,7 @@ func initBuiltInCert() {
CryptoAlgorithm: "RS256",
BitSize: 4096,
ExpireInYears: 20,
PublicKey: tokenJwtPublicKey,
Certificate: tokenJwtCertificate,
PrivateKey: tokenJwtPrivateKey,
}
AddCert(cert)
@ -221,3 +236,58 @@ func initBuiltInProvider() {
}
AddProvider(provider)
}
func initWebAuthn() {
gob.Register(webauthn.SessionData{})
}
func initBuiltInModel() {
model := GetModel("built-in/model-built-in")
if model != nil {
return
}
model = &Model{
Owner: "built-in",
Name: "model-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Model",
IsEnabled: true,
ModelText: `[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`,
}
AddModel(model)
}
func initBuiltInPermission() {
permission := GetPermission("built-in/permission-built-in")
if permission != nil {
return
}
permission = &Permission{
Owner: "built-in",
Name: "permission-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Permission",
Users: []string{"built-in/*"},
Roles: []string{},
Domains: []string{},
Model: "model-built-in",
ResourceType: "Application",
Resources: []string{"app-built-in"},
Actions: []string{"Read", "Write", "Admin"},
Effect: "Allow",
IsEnabled: true,
}
AddPermission(permission)
}

148
object/init_data.go Normal file
View File

@ -0,0 +1,148 @@
// 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 object
import "github.com/casdoor/casdoor/util"
type InitData struct {
Organizations []*Organization `json:"organizations"`
Applications []*Application `json:"applications"`
Users []*User `json:"users"`
Certs []*Cert `json:"certs"`
Providers []*Provider `json:"providers"`
Ldaps []*Ldap `json:"ldaps"`
}
func InitFromFile() {
initData := readInitDataFromFile("./init_data.json")
if initData != nil {
for _, organization := range initData.Organizations {
initDefinedOrganization(organization)
}
for _, provider := range initData.Providers {
initDefinedProvider(provider)
}
for _, user := range initData.Users {
initDefinedUser(user)
}
for _, application := range initData.Applications {
initDefinedApplication(application)
}
for _, cert := range initData.Certs {
initDefinedCert(cert)
}
for _, ldap := range initData.Ldaps {
initDefinedLdap(ldap)
}
}
}
func readInitDataFromFile(filePath string) *InitData {
if !util.FileExist(filePath) {
return nil
}
s := util.ReadStringFromPath(filePath)
data := &InitData{}
err := util.JsonToStruct(s, data)
if err != nil {
panic(err)
}
return data
}
func initDefinedOrganization(organization *Organization) {
existed := getOrganization(organization.Owner, organization.Name)
if existed != nil {
return
}
organization.CreatedTime = util.GetCurrentTime()
organization.AccountItems = []*AccountItem{
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
}
AddOrganization(organization)
}
func initDefinedApplication(application *Application) {
existed := getApplication(application.Owner, application.Name)
if existed != nil {
return
}
application.CreatedTime = util.GetCurrentTime()
AddApplication(application)
}
func initDefinedUser(user *User) {
existed := getUser(user.Owner, user.Name)
if existed != nil {
return
}
user.CreatedTime = util.GetCurrentTime()
user.Id = util.GenerateId()
user.Properties = make(map[string]string)
AddUser(user)
}
func initDefinedCert(cert *Cert) {
existed := getCert(cert.Owner, cert.Name)
if existed != nil {
return
}
cert.CreatedTime = util.GetCurrentTime()
AddCert(cert)
}
func initDefinedLdap(ldap *Ldap) {
existed := GetLdap(ldap.Id)
if existed != nil {
return
}
AddLdap(ldap)
}
func initDefinedProvider(provider *Provider) {
existed := GetProvider(provider.GetId())
if existed != nil {
return
}
AddProvider(provider)
}

View File

@ -19,7 +19,7 @@ import (
"fmt"
"strings"
"github.com/astaxie/beego"
"github.com/beego/beego"
"github.com/casdoor/casdoor/util"
goldap "github.com/go-ldap/ldap/v3"
"github.com/thanhpk/randstr"
@ -56,7 +56,7 @@ type ldapUser struct {
Uid string
Cn string
GidNumber string
//Gcn string
// Gcn string
Uuid string
Mail string
Email string
@ -73,7 +73,7 @@ type LdapRespUser struct {
Uid string `json:"uid"`
Cn string `json:"cn"`
GroupId string `json:"groupId"`
//GroupName string `json:"groupName"`
// GroupName string `json:"groupName"`
Uuid string `json:"uuid"`
Email string `json:"email"`
Phone string `json:"phone"`
@ -208,11 +208,15 @@ func GetLdapConn(host string, port int, adminUser string, adminPasswd string) (*
func (l *ldapConn) GetLdapUsers(baseDn string) ([]ldapUser, error) {
SearchFilter := "(objectClass=posixAccount)"
SearchAttributes := []string{"uidNumber", "uid", "cn", "gidNumber", "entryUUID", "mail", "email",
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress"}
SearchAttributes := []string{
"uidNumber", "uid", "cn", "gidNumber", "entryUUID", "mail", "email",
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
}
SearchFilterMsAD := "(objectClass=user)"
SearchAttributesMsAD := []string{"uidNumber", "sAMAccountName", "cn", "gidNumber", "entryUUID", "mail", "email",
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress"}
SearchAttributesMsAD := []string{
"uidNumber", "sAMAccountName", "cn", "gidNumber", "entryUUID", "mail", "email",
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
}
var searchReq *goldap.SearchRequest
if l.IsAD {
searchReq = goldap.NewSearchRequest(baseDn,
@ -405,6 +409,7 @@ func SyncLdapUsers(owner string, users []LdapRespUser, ldapId string) (*[]LdapRe
}
}
}
if !found && !AddUser(&User{
Owner: owner,
Name: buildLdapUserName(user.Uid, user.UidNumber),
@ -459,7 +464,7 @@ func CheckLdapUuidExist(owner string, uuids []string) []string {
}
}
for uuid, _ := range existUuidSet {
for uuid := range existUuidSet {
existUuids = append(existUuids, uuid)
}
return existUuids

View File

@ -5,7 +5,7 @@ import (
"sync"
"time"
"github.com/astaxie/beego/logs"
"github.com/beego/beego/logs"
"github.com/casdoor/casdoor/util"
)
@ -31,7 +31,8 @@ func GetLdapAutoSynchronizer() *LdapAutoSynchronizer {
return globalLdapAutoSynchronizer
}
//start autosync for specified ldap, old existing autosync goroutine will be ceased
// StartAutoSync
// start autosync for specified ldap, old existing autosync goroutine will be ceased
func (l *LdapAutoSynchronizer) StartAutoSync(ldapId string) error {
l.Lock()
defer l.Unlock()
@ -48,7 +49,7 @@ func (l *LdapAutoSynchronizer) StartAutoSync(ldapId string) error {
stopChan := make(chan struct{})
l.ldapIdToStopChan[ldapId] = stopChan
logs.Info(fmt.Sprintf("autoSync started for %s", ldap.Id))
util.SafeGoroutine(func() {l.syncRoutine(ldap, stopChan)})
util.SafeGoroutine(func() { l.syncRoutine(ldap, stopChan) })
return nil
}
@ -61,7 +62,7 @@ func (l *LdapAutoSynchronizer) StopAutoSync(ldapId string) {
}
}
//autosync goroutine
// autosync goroutine
func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
ticker := time.NewTicker(time.Duration(ldap.AutoSync) * time.Minute)
defer ticker.Stop()
@ -74,7 +75,7 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
}
UpdateLdapSyncTime(ldap.Id)
//fetch all users
// fetch all users
conn, err := GetLdapConn(ldap.Host, ldap.Port, ldap.Admin, ldap.Passwd)
if err != nil {
logs.Warning(fmt.Sprintf("autoSync failed for %s, error %s", ldap.Id, err))
@ -93,10 +94,10 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(*existed), len(*existed)))
}
}
}
//start all autosync goroutine for existing ldap servers in each organizations
// LdapAutoSynchronizerStartUpAll
// start all autosync goroutine for existing ldap servers in each organizations
func (l *LdapAutoSynchronizer) LdapAutoSynchronizerStartUpAll() {
organizations := []*Organization{}
err := adapter.Engine.Desc("created_time").Find(&organizations)

74
object/ldapserver.go Normal file
View File

@ -0,0 +1,74 @@
// 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 object
import (
"fmt"
"log"
"strings"
"github.com/forestmgy/ldapserver"
)
func GetNameAndOrgFromDN(DN string) (string, string, string) {
DNValue := strings.Split(DN, ",")
if len(DNValue) == 1 || strings.ToLower(DNValue[0])[0] != 'c' || strings.ToLower(DNValue[1])[0] != 'o' {
return "", "", "please use correct Admin Name format like cn=xxx,ou=xxx,dc=example,dc=com"
}
return DNValue[0][3:], DNValue[1][3:], ""
}
func GetUserNameAndOrgFromBaseDnAndFilter(baseDN, filter string) (string, string, int) {
if !strings.Contains(baseDN, "ou=") || !strings.Contains(filter, "cn=") {
return "", "", ldapserver.LDAPResultInvalidDNSyntax
}
name := getUserNameFromFilter(filter)
_, org, _ := GetNameAndOrgFromDN(fmt.Sprintf("cn=%s,", name) + baseDN)
errCode := ldapserver.LDAPResultSuccess
return name, org, errCode
}
func getUserNameFromFilter(filter string) string {
nameIndex := strings.Index(filter, "cn=")
var name string
for i := nameIndex + 3; filter[i] != ')'; i++ {
name = name + string(filter[i])
}
return name
}
func GetFilteredUsers(m *ldapserver.Message, name, org string) ([]*User, int) {
var filteredUsers []*User
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
if m.Client.OrgName == "built-in" && org == "*" {
filteredUsers = GetGlobalUsers()
return filteredUsers, ldapserver.LDAPResultSuccess
} else if m.Client.OrgName == "built-in" || org == m.Client.OrgName {
filteredUsers = GetUsers(org)
return filteredUsers, ldapserver.LDAPResultSuccess
} else {
return nil, ldapserver.LDAPResultInsufficientAccessRights
}
} else {
hasPermission, err := CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), org, true)
if !hasPermission {
log.Printf("ErrMsg = %v", err.Error())
return nil, ldapserver.LDAPResultInsufficientAccessRights
}
user := getUser(org, name)
filteredUsers = append(filteredUsers, user)
return filteredUsers, ldapserver.LDAPResultSuccess
}
}

Some files were not shown because too many files have changed in this diff Show More