2022-02-13 23:39:27 +08:00
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
2021-03-06 16:39:17 +08:00
//
// 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.
2021-02-11 22:56:08 +08:00
package object
2021-05-01 16:50:47 +08:00
import (
"fmt"
2024-01-15 18:12:23 +08:00
"regexp"
2022-04-16 15:10:03 +08:00
"strings"
2022-08-17 01:39:53 +08:00
"time"
2022-08-16 00:14:26 +08:00
"unicode"
2021-05-01 17:45:01 +08:00
2022-01-20 14:11:46 +08:00
"github.com/casdoor/casdoor/cred"
2023-04-25 23:05:53 +08:00
"github.com/casdoor/casdoor/form"
2022-10-23 15:16:24 +08:00
"github.com/casdoor/casdoor/i18n"
2022-01-20 14:11:46 +08:00
"github.com/casdoor/casdoor/util"
2021-12-10 22:45:01 +08:00
goldap "github.com/go-ldap/ldap/v3"
2021-05-01 16:50:47 +08:00
)
2022-08-17 01:39:53 +08:00
const (
2024-01-13 02:09:18 +08:00
DefaultFailedSigninLimit = 5
2024-01-13 02:12:29 +08:00
DefaultFailedSigninFrozenTime = 15
2022-08-17 01:39:53 +08:00
)
2024-01-15 18:12:23 +08:00
func CheckUserSignup ( application * Application , organization * Organization , authForm * form . AuthForm , lang string ) string {
2021-06-17 00:49:02 +08:00
if organization == nil {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Organization does not exist" )
2021-06-17 00:49:02 +08:00
}
if application . IsSignupItemVisible ( "Username" ) {
2024-01-15 18:12:23 +08:00
if len ( authForm . Username ) <= 1 {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Username must have at least 2 characters" )
2022-08-16 00:14:26 +08:00
}
2024-01-15 18:12:23 +08:00
if unicode . IsDigit ( rune ( authForm . Username [ 0 ] ) ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Username cannot start with a digit" )
2022-08-16 00:14:26 +08:00
}
2024-01-15 18:12:23 +08:00
if util . IsEmailValid ( authForm . Username ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Username cannot be an email address" )
2022-08-16 00:14:26 +08:00
}
2024-01-15 18:12:23 +08:00
if util . ReWhiteSpace . MatchString ( authForm . Username ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Username cannot contain white spaces" )
2022-08-16 00:14:26 +08:00
}
2023-01-10 22:34:08 +08:00
2024-01-15 18:12:23 +08:00
if msg := CheckUsername ( authForm . Username , lang ) ; msg != "" {
2022-10-17 18:01:01 +08:00
return msg
}
2024-01-15 18:12:23 +08:00
if HasUserByField ( organization . Name , "name" , authForm . Username ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Username already exists" )
2021-06-17 00:49:02 +08:00
}
2024-01-15 18:12:23 +08:00
if HasUserByField ( organization . Name , "email" , authForm . Email ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Email already exists" )
2022-08-16 00:14:26 +08:00
}
2024-01-15 18:12:23 +08:00
if HasUserByField ( organization . Name , "phone" , authForm . Phone ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Phone already exists" )
2022-08-16 00:14:26 +08:00
}
2021-06-17 00:49:02 +08:00
}
2021-05-15 13:54:23 +08:00
2023-08-25 21:16:21 +08:00
if application . IsSignupItemVisible ( "Password" ) {
2024-01-15 18:12:23 +08:00
msg := CheckPasswordComplexityByOrg ( organization , authForm . Password )
2023-08-25 21:16:21 +08:00
if msg != "" {
return msg
}
2021-02-11 22:56:08 +08:00
}
2021-06-17 00:49:02 +08:00
if application . IsSignupItemVisible ( "Email" ) {
2024-01-15 18:12:23 +08:00
if authForm . Email == "" {
2021-11-09 20:28:27 +08:00
if application . IsSignupItemRequired ( "Email" ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Email cannot be empty" )
2021-11-09 20:28:27 +08:00
}
2023-03-15 23:44:38 +08:00
} else {
2024-01-15 18:12:23 +08:00
if HasUserByField ( organization . Name , "email" , authForm . Email ) {
2023-03-15 23:44:38 +08:00
return i18n . Translate ( lang , "check:Email already exists" )
2024-01-15 18:12:23 +08:00
} else if ! util . IsEmailValid ( authForm . Email ) {
2023-03-15 23:44:38 +08:00
return i18n . Translate ( lang , "check:Email is invalid" )
}
2021-06-17 00:49:02 +08:00
}
}
if application . IsSignupItemVisible ( "Phone" ) {
2024-01-15 18:12:23 +08:00
if authForm . Phone == "" {
2021-11-09 20:28:27 +08:00
if application . IsSignupItemRequired ( "Phone" ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Phone cannot be empty" )
2021-11-09 20:28:27 +08:00
}
2023-03-15 23:44:38 +08:00
} else {
2024-01-15 18:12:23 +08:00
if HasUserByField ( organization . Name , "phone" , authForm . Phone ) {
2023-03-15 23:44:38 +08:00
return i18n . Translate ( lang , "check:Phone already exists" )
2024-01-15 18:12:23 +08:00
} else if ! util . IsPhoneAllowInRegin ( authForm . CountryCode , organization . CountryCodes ) {
2023-03-15 23:44:38 +08:00
return i18n . Translate ( lang , "check:Your region is not allow to signup by phone" )
2024-01-15 18:12:23 +08:00
} else if ! util . IsPhoneValid ( authForm . Phone , authForm . CountryCode ) {
2023-03-15 23:44:38 +08:00
return i18n . Translate ( lang , "check:Phone number is invalid" )
}
2021-06-17 00:49:02 +08:00
}
}
if application . IsSignupItemVisible ( "Display name" ) {
2024-01-15 18:12:23 +08:00
if application . GetSignupItemRule ( "Display name" ) == "First, last" && ( authForm . FirstName != "" || authForm . LastName != "" ) {
if authForm . FirstName == "" {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:FirstName cannot be blank" )
2024-01-15 18:12:23 +08:00
} else if authForm . LastName == "" {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:LastName cannot be blank" )
2022-02-27 14:02:52 +08:00
}
} else {
2024-01-15 18:12:23 +08:00
if authForm . Name == "" {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:DisplayName cannot be blank" )
2022-02-27 14:02:52 +08:00
} else if application . GetSignupItemRule ( "Display name" ) == "Real name" {
2024-01-15 18:12:23 +08:00
if ! isValidRealName ( authForm . Name ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:DisplayName is not valid real name" )
2022-02-27 14:02:52 +08:00
}
2021-06-17 11:55:06 +08:00
}
2021-06-17 00:49:02 +08:00
}
}
if application . IsSignupItemVisible ( "Affiliation" ) {
2024-01-15 18:12:23 +08:00
if authForm . Affiliation == "" {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Affiliation cannot be blank" )
2021-06-17 00:49:02 +08:00
}
}
2024-01-15 18:12:23 +08:00
for _ , signupItem := range application . SignupItems {
if signupItem . Regex == "" {
continue
}
isString , value := form . GetAuthFormFieldValue ( authForm , signupItem . Name )
if ! isString {
continue
}
regexSignupItem , err := regexp . Compile ( signupItem . Regex )
if err != nil {
return err . Error ( )
}
matched := regexSignupItem . MatchString ( value )
if ! matched {
return fmt . Sprintf ( i18n . Translate ( lang , "check:The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"" ) , value , signupItem . Name , application . Name )
}
}
2021-06-17 00:49:02 +08:00
return ""
2021-02-11 22:56:08 +08:00
}
2024-01-22 02:25:13 +08:00
func CheckInvitationCode ( application * Application , organization * Organization , authForm * form . AuthForm , lang string ) ( * Invitation , string ) {
if authForm . InvitationCode == "" {
if application . IsSignupItemRequired ( "Invitation code" ) {
return nil , i18n . Translate ( lang , "check:Invitation code cannot be blank" )
} else {
return nil , ""
}
}
invitations , err := GetInvitations ( organization . Name )
if err != nil {
return nil , err . Error ( )
}
errMsg := ""
for _ , invitation := range invitations {
if invitation . Application != application . Name && invitation . Application != "All" {
continue
}
if isValid , msg := invitation . IsInvitationCodeValid ( application , authForm . InvitationCode , authForm . Username , authForm . Email , authForm . Phone , lang ) ; isValid {
return invitation , msg
} else if msg != "" && errMsg == "" {
errMsg = msg
}
}
if errMsg != "" {
return nil , errMsg
} else {
return nil , i18n . Translate ( lang , "check:Invitation code is invalid" )
}
}
2024-02-02 21:12:56 +08:00
func CheckInvitationDefaultCode ( code string , defaultCode string , lang string ) error {
if matched , err := util . IsInvitationCodeMatch ( code , defaultCode ) ; err != nil {
return err
} else if ! matched {
return fmt . Errorf ( i18n . Translate ( lang , "check:Default code does not match the code's matching rules" ) )
}
return nil
}
2023-11-19 19:58:07 +08:00
func checkSigninErrorTimes ( user * User , lang string ) error {
2024-01-13 02:12:29 +08:00
failedSigninLimit , failedSigninFrozenTime , err := GetFailedSigninConfigByUser ( user )
2023-12-20 22:29:53 +08:00
if err != nil {
return err
}
if user . SigninWrongTimes >= failedSigninLimit {
2022-08-17 01:39:53 +08:00
lastSignWrongTime , _ := time . Parse ( time . RFC3339 , user . LastSigninWrongTime )
passedTime := time . Now ( ) . UTC ( ) . Sub ( lastSignWrongTime )
2024-01-13 02:12:29 +08:00
minutes := failedSigninFrozenTime - int ( passedTime . Minutes ( ) )
2022-08-17 01:39:53 +08:00
// deny the login if the error times is greater than the limit and the last login time is less than the duration
2023-01-06 19:49:00 +08:00
if minutes > 0 {
2023-11-19 19:58:07 +08:00
return fmt . Errorf ( i18n . Translate ( lang , "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again" ) , minutes )
2022-08-17 01:39:53 +08:00
}
// reset the error times
user . SigninWrongTimes = 0
2023-11-19 19:58:07 +08:00
_ , err := UpdateUser ( user . GetId ( ) , user , [ ] string { "signin_wrong_times" } , false )
return err
2022-08-17 01:39:53 +08:00
}
2023-11-19 19:58:07 +08:00
return nil
2022-08-17 01:39:53 +08:00
}
2023-11-19 19:58:07 +08:00
func CheckPassword ( user * User , password string , lang string , options ... bool ) error {
2023-04-22 16:16:25 +08:00
enableCaptcha := false
if len ( options ) > 0 {
enableCaptcha = options [ 0 ]
}
2022-08-17 01:39:53 +08:00
// check the login error times
2023-04-22 16:16:25 +08:00
if ! enableCaptcha {
2023-11-19 19:58:07 +08:00
err := checkSigninErrorTimes ( user , lang )
if err != nil {
return err
2023-04-22 16:16:25 +08:00
}
2022-08-17 01:39:53 +08:00
}
2023-05-30 15:49:39 +08:00
organization , err := GetOrganizationByUser ( user )
if err != nil {
2023-11-19 19:58:07 +08:00
return err
2023-05-30 15:49:39 +08:00
}
2021-09-04 22:20:47 +08:00
if organization == nil {
2023-11-19 19:58:07 +08:00
return fmt . Errorf ( i18n . Translate ( lang , "check:Organization does not exist" ) )
2021-09-04 22:20:47 +08:00
}
2021-11-04 21:08:43 +08:00
2025-01-28 21:13:59 +08:00
if password == "" {
return fmt . Errorf ( i18n . Translate ( lang , "check:Password cannot be empty" ) )
}
2023-05-16 20:14:05 +08:00
passwordType := user . PasswordType
if passwordType == "" {
passwordType = organization . PasswordType
}
credManager := cred . GetCredManager ( passwordType )
2021-11-04 21:08:43 +08:00
if credManager != nil {
2021-12-22 20:56:22 +08:00
if organization . MasterPassword != "" {
2025-02-14 16:24:38 +08:00
if password == organization . MasterPassword || credManager . IsPasswordCorrect ( password , organization . MasterPassword , "" , organization . PasswordSalt ) {
2023-11-19 19:58:07 +08:00
return resetUserSigninErrorTimes ( user )
2021-12-22 20:56:22 +08:00
}
2021-11-06 21:14:53 +08:00
}
2021-12-22 13:56:32 +08:00
if credManager . IsPasswordCorrect ( password , user . Password , user . PasswordSalt , organization . PasswordSalt ) {
2023-11-19 19:58:07 +08:00
return resetUserSigninErrorTimes ( user )
2021-05-03 10:13:32 +08:00
}
2022-08-17 01:39:53 +08:00
2023-04-22 16:16:25 +08:00
return recordSigninErrorInfo ( user , lang , enableCaptcha )
2021-05-03 10:13:32 +08:00
} else {
2023-11-19 19:58:07 +08:00
return fmt . Errorf ( i18n . Translate ( lang , "check:unsupported password type: %s" ) , organization . PasswordType )
2021-05-03 10:13:32 +08:00
}
}
2023-06-17 00:01:20 +08:00
func CheckPasswordComplexityByOrg ( organization * Organization , password string ) string {
errorMsg := checkPasswordComplexity ( password , organization . PasswordOptions )
return errorMsg
}
func CheckPasswordComplexity ( user * User , password string ) string {
organization , _ := GetOrganizationByUser ( user )
return CheckPasswordComplexityByOrg ( organization , password )
}
2024-12-09 17:06:24 +09:00
func CheckLdapUserPassword ( user * User , password string , lang string ) error {
2023-05-30 15:49:39 +08:00
ldaps , err := GetLdaps ( user . Owner )
if err != nil {
2023-11-19 19:58:07 +08:00
return err
2023-05-30 15:49:39 +08:00
}
2021-12-10 22:45:01 +08:00
ldapLoginSuccess := false
2023-04-13 14:12:31 +08:00
hit := false
2021-12-10 22:45:01 +08:00
for _ , ldapServer := range ldaps {
2023-03-15 11:12:31 +08:00
conn , err := ldapServer . GetLdapConn ( )
2021-12-10 22:45:01 +08:00
if err != nil {
continue
}
2023-04-13 14:12:31 +08:00
searchReq := goldap . NewSearchRequest ( ldapServer . BaseDn , goldap . ScopeWholeSubtree , goldap . NeverDerefAliases ,
2023-05-19 21:16:59 +08:00
0 , 0 , false , ldapServer . buildAuthFilterString ( user ) , [ ] string { } , nil )
2023-04-13 14:12:31 +08:00
2021-12-10 22:45:01 +08:00
searchResult , err := conn . Conn . Search ( searchReq )
if err != nil {
2023-12-02 17:51:25 +08:00
conn . Close ( )
2023-11-19 19:58:07 +08:00
return err
2021-12-10 22:45:01 +08:00
}
if len ( searchResult . Entries ) == 0 {
2023-12-02 17:51:25 +08:00
conn . Close ( )
2021-12-10 22:45:01 +08:00
continue
2023-04-13 14:12:31 +08:00
}
if len ( searchResult . Entries ) > 1 {
2023-12-02 17:51:25 +08:00
conn . Close ( )
2023-11-19 19:58:07 +08:00
return fmt . Errorf ( i18n . Translate ( lang , "check:Multiple accounts with same uid, please check your ldap server" ) )
2021-12-10 22:45:01 +08:00
}
2023-04-13 14:12:31 +08:00
hit = true
2021-12-10 22:45:01 +08:00
dn := searchResult . Entries [ 0 ] . DN
2023-12-02 17:51:25 +08:00
if err = conn . Conn . Bind ( dn , password ) ; err == nil {
2021-12-10 22:45:01 +08:00
ldapLoginSuccess = true
2023-12-02 17:51:25 +08:00
conn . Close ( )
2021-12-10 22:45:01 +08:00
break
}
2023-12-02 17:51:25 +08:00
conn . Close ( )
2021-12-10 22:45:01 +08:00
}
if ! ldapLoginSuccess {
2023-04-13 14:12:31 +08:00
if ! hit {
2023-11-19 19:58:07 +08:00
return fmt . Errorf ( "user not exist" )
2023-04-13 14:12:31 +08:00
}
2023-11-19 19:58:07 +08:00
return fmt . Errorf ( i18n . Translate ( lang , "check:LDAP user name or password incorrect" ) )
2021-12-10 22:45:01 +08:00
}
2024-01-22 13:42:11 +08:00
return resetUserSigninErrorTimes ( user )
2021-12-10 22:45:01 +08:00
}
2023-11-19 19:58:07 +08:00
func CheckUserPassword ( organization string , username string , password string , lang string , options ... bool ) ( * User , error ) {
2023-04-22 16:16:25 +08:00
enableCaptcha := false
2024-01-08 21:07:34 +08:00
isSigninViaLdap := false
isPasswordWithLdapEnabled := false
2023-04-22 16:16:25 +08:00
if len ( options ) > 0 {
enableCaptcha = options [ 0 ]
2024-01-08 21:07:34 +08:00
isSigninViaLdap = options [ 1 ]
isPasswordWithLdapEnabled = options [ 2 ]
2023-04-22 16:16:25 +08:00
}
2023-05-30 15:49:39 +08:00
user , err := GetUserByFields ( organization , username )
if err != nil {
2023-11-19 19:58:07 +08:00
return nil , err
2023-05-30 15:49:39 +08:00
}
2023-05-23 17:54:51 +08:00
if user == nil || user . IsDeleted {
2023-11-19 19:58:07 +08:00
return nil , fmt . Errorf ( i18n . Translate ( lang , "general:The user: %s doesn't exist" ) , util . GetId ( organization , username ) )
2021-02-11 22:56:08 +08:00
}
2021-05-05 23:32:21 +08:00
if user . IsForbidden {
2023-11-19 19:58:07 +08:00
return nil , fmt . Errorf ( i18n . Translate ( lang , "check:The user is forbidden to sign in, please contact the administrator" ) )
2021-05-05 23:32:21 +08:00
}
2024-01-08 21:07:34 +08:00
if isSigninViaLdap {
if user . Ldap == "" {
return nil , fmt . Errorf ( i18n . Translate ( lang , "check:The user: %s doesn't exist in LDAP server" ) , username )
}
}
2024-09-07 20:55:14 +08:00
if user . Ldap != "" {
if ! isSigninViaLdap && ! isPasswordWithLdapEnabled {
2024-01-08 21:07:34 +08:00
return nil , fmt . Errorf ( i18n . Translate ( lang , "check:password or code is incorrect" ) )
}
2024-01-09 21:53:44 +08:00
// check the login error times
if ! enableCaptcha {
err = checkSigninErrorTimes ( user , lang )
if err != nil {
return nil , err
}
}
2023-11-19 19:58:07 +08:00
// only for LDAP users
2024-12-09 17:06:24 +09:00
err = CheckLdapUserPassword ( user , password , lang )
2023-11-19 19:58:07 +08:00
if err != nil {
if err . Error ( ) == "user not exist" {
return nil , fmt . Errorf ( i18n . Translate ( lang , "check:The user: %s doesn't exist in LDAP server" ) , username )
2023-04-13 14:12:31 +08:00
}
2024-01-09 21:53:44 +08:00
return nil , recordSigninErrorInfo ( user , lang , enableCaptcha )
2023-04-13 14:12:31 +08:00
}
2022-03-28 17:19:58 +08:00
} else {
2023-11-19 19:58:07 +08:00
err = CheckPassword ( user , password , lang , enableCaptcha )
if err != nil {
return nil , err
2022-03-12 21:06:38 +08:00
}
2024-11-19 21:06:52 +08:00
err = checkPasswordExpired ( user , lang )
if err != nil {
return nil , err
}
2021-02-11 22:56:08 +08:00
}
2024-11-19 21:06:52 +08:00
2023-11-19 19:58:07 +08:00
return user , nil
2021-02-11 22:56:08 +08:00
}
2022-01-26 19:36:36 +08:00
2023-04-06 23:06:18 +08:00
func CheckUserPermission ( requestUserId , userId string , strict bool , lang string ) ( bool , error ) {
2022-04-16 15:10:03 +08:00
if requestUserId == "" {
2023-01-06 20:12:32 +08:00
return false , fmt . Errorf ( i18n . Translate ( lang , "general:Please login first" ) )
2022-04-16 15:10:03 +08:00
}
2023-04-06 23:06:18 +08:00
userOwner := util . GetOwnerFromId ( userId )
2022-07-31 10:54:41 +08:00
if userId != "" {
2023-05-30 15:49:39 +08:00
targetUser , err := GetUser ( userId )
if err != nil {
2023-11-19 19:58:07 +08:00
return false , err
2023-05-30 15:49:39 +08:00
}
2022-07-31 10:54:41 +08:00
if targetUser == nil {
2023-05-12 13:03:43 +08:00
if strings . HasPrefix ( requestUserId , "built-in/" ) {
return true , nil
}
2023-01-06 20:12:32 +08:00
return false , fmt . Errorf ( i18n . Translate ( lang , "general:The user: %s doesn't exist" ) , userId )
2022-07-31 10:54:41 +08:00
}
userOwner = targetUser . Owner
2022-04-16 15:10:03 +08:00
}
hasPermission := false
2024-04-24 01:10:38 +08:00
if IsAppUser ( requestUserId ) {
2022-04-16 15:10:03 +08:00
hasPermission = true
} else {
2023-05-30 15:49:39 +08:00
requestUser , err := GetUser ( requestUserId )
if err != nil {
return false , err
}
2022-04-16 15:10:03 +08:00
if requestUser == nil {
2022-12-07 13:13:23 +08:00
return false , fmt . Errorf ( i18n . Translate ( lang , "check:Session outdated, please login again" ) )
2022-04-16 15:10:03 +08:00
}
2023-08-19 12:23:15 +08:00
if requestUser . IsGlobalAdmin ( ) {
2022-04-16 15:10:03 +08:00
hasPermission = true
} else if requestUserId == userId {
hasPermission = true
2022-07-31 10:54:41 +08:00
} else if userOwner == requestUser . Owner {
2022-04-16 15:10:03 +08:00
if strict {
hasPermission = requestUser . IsAdmin
} else {
hasPermission = true
}
}
}
2023-01-06 20:12:32 +08:00
return hasPermission , fmt . Errorf ( i18n . Translate ( lang , "auth:Unauthorized operation" ) )
2022-07-13 00:34:35 +08:00
}
2023-09-15 02:47:53 +08:00
func CheckLoginPermission ( userId string , application * Application ) ( bool , error ) {
2023-10-31 22:36:56 +08:00
owner , _ := util . GetOwnerAndNameFromId ( userId )
if owner == "built-in" {
2023-05-18 13:36:16 +08:00
return true , nil
}
2023-05-30 15:49:39 +08:00
permissions , err := GetPermissions ( application . Organization )
if err != nil {
return false , err
}
2023-10-13 15:41:23 +08:00
allowPermissionCount := 0
denyPermissionCount := 0
2023-09-15 02:47:53 +08:00
allowCount := 0
denyCount := 0
2022-07-13 00:34:35 +08:00
for _ , permission := range permissions {
2023-11-22 00:03:18 +08:00
if ! permission . IsEnabled || permission . State != "Approved" || permission . ResourceType != "Application" || ! permission . isResourceHit ( application . Name ) {
2022-07-13 00:50:32 +08:00
continue
}
2023-10-17 01:35:13 -05:00
if ! permission . isUserHit ( userId ) && ! permission . isRoleHit ( userId ) {
2023-10-13 15:41:23 +08:00
if permission . Effect == "Allow" {
allowPermissionCount += 1
} else {
denyPermissionCount += 1
}
continue
2022-07-13 00:34:35 +08:00
}
2022-07-13 00:50:32 +08:00
2023-10-22 02:30:29 +08:00
enforcer , err := getPermissionEnforcer ( permission )
if err != nil {
return false , err
}
2023-09-15 02:47:53 +08:00
var isAllowed bool
isAllowed , err = enforcer . Enforce ( userId , application . Name , "Read" )
if err != nil {
return false , err
}
if isAllowed {
if permission . Effect == "Allow" {
allowCount += 1
2022-09-02 12:03:13 +08:00
}
2023-09-15 02:47:53 +08:00
} else {
if permission . Effect == "Deny" {
denyCount += 1
2022-12-23 14:06:02 +08:00
}
2022-07-13 00:50:32 +08:00
}
2022-07-13 00:34:35 +08:00
}
2023-09-15 02:47:53 +08:00
2023-10-13 15:41:23 +08:00
// Deny-override, if one deny is found, then deny
2023-09-15 02:47:53 +08:00
if denyCount > 0 {
return false , nil
2023-10-13 15:41:23 +08:00
} else if allowCount > 0 {
return true , nil
}
// For no-allow and no-deny condition
// If only allow permissions exist, we suppose it's Deny-by-default, aka no-allow means deny
// Otherwise, it's Allow-by-default, aka no-deny means allow
if allowPermissionCount > 0 && denyPermissionCount == 0 {
return false , nil
2023-09-15 02:47:53 +08:00
}
return true , nil
2022-07-13 00:50:32 +08:00
}
2022-10-10 19:58:02 +08:00
2022-10-23 15:16:24 +08:00
func CheckUsername ( username string , lang string ) string {
2022-10-17 18:01:01 +08:00
if username == "" {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check:Empty username." )
2025-03-01 00:44:34 +08:00
} else if len ( username ) > 255 {
return i18n . Translate ( lang , "check:Username is too long (maximum is 255 characters)." )
2022-10-10 19:58:02 +08:00
}
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
2023-06-29 21:44:14 +08:00
if ! util . ReUserName . MatchString ( username ) {
2022-12-07 13:13:23 +08:00
return i18n . Translate ( lang , "check: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." )
2022-10-10 19:58:02 +08:00
}
return ""
}
2022-10-28 13:38:14 +08:00
2024-11-05 20:38:47 +08:00
func CheckUsernameWithEmail ( username string , lang string ) string {
if username == "" {
return i18n . Translate ( lang , "check:Empty username." )
2025-03-01 00:44:34 +08:00
} else if len ( username ) > 255 {
return i18n . Translate ( lang , "check:Username is too long (maximum is 255 characters)." )
2024-11-05 20:38:47 +08:00
}
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
if ! util . ReUserNameWithEmail . MatchString ( username ) {
return i18n . Translate ( lang , "check:Username supports email format. Also 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. Also pay attention to the email format." )
}
return ""
}
2023-04-09 10:35:30 +08:00
func CheckUpdateUser ( oldUser , user * User , lang string ) string {
2023-01-10 22:34:08 +08:00
if oldUser . Name != user . Name {
2024-11-06 08:34:13 +08:00
organizationName := oldUser . Owner
if organizationName == "" {
organizationName = user . Owner
}
organization , err := getOrganization ( "admin" , organizationName )
2024-11-05 20:38:47 +08:00
if err != nil {
return err . Error ( )
}
if organization == nil {
2024-11-06 08:34:13 +08:00
return fmt . Sprintf ( i18n . Translate ( lang , "auth:The organization: %s does not exist" ) , organizationName )
2023-01-17 16:08:37 +07:00
}
2024-11-06 08:34:13 +08:00
2024-11-05 20:38:47 +08:00
if organization . UseEmailAsUsername {
if msg := CheckUsernameWithEmail ( user . Name , lang ) ; msg != "" {
return msg
}
} else {
if msg := CheckUsername ( user . Name , lang ) ; msg != "" {
return msg
}
}
2023-01-10 22:34:08 +08:00
if HasUserByField ( user . Owner , "name" , user . Name ) {
return i18n . Translate ( lang , "check:Username already exists" )
}
}
if oldUser . Email != user . Email {
2023-08-31 23:44:40 +08:00
if HasUserByField ( user . Owner , "email" , user . Email ) {
2023-01-10 22:34:08 +08:00
return i18n . Translate ( lang , "check:Email already exists" )
}
}
if oldUser . Phone != user . Phone {
if HasUserByField ( user . Owner , "phone" , user . Phone ) {
return i18n . Translate ( lang , "check:Phone already exists" )
}
}
2024-10-15 20:40:14 +08:00
if oldUser . IpWhitelist != user . IpWhitelist {
if err := CheckIpWhitelist ( user . IpWhitelist , lang ) ; err != nil {
return err . Error ( )
}
}
2023-01-10 22:34:08 +08:00
return ""
}
2023-05-30 15:49:39 +08:00
func CheckToEnableCaptcha ( application * Application , organization , username string ) ( bool , error ) {
2022-10-28 13:38:14 +08:00
if len ( application . Providers ) == 0 {
2023-05-30 15:49:39 +08:00
return false , nil
2022-10-28 13:38:14 +08:00
}
for _ , providerItem := range application . Providers {
if providerItem . Provider == nil {
continue
}
2023-03-05 20:31:46 +08:00
if providerItem . Provider . Category == "Captcha" {
2023-04-22 16:16:25 +08:00
if providerItem . Rule == "Dynamic" {
2023-05-30 15:49:39 +08:00
user , err := GetUserByFields ( organization , username )
if err != nil {
return false , err
}
2023-12-20 22:29:53 +08:00
2024-01-13 02:09:18 +08:00
failedSigninLimit := application . FailedSigninLimit
if failedSigninLimit == 0 {
failedSigninLimit = DefaultFailedSigninLimit
2023-12-20 22:29:53 +08:00
}
2024-01-13 02:09:18 +08:00
2023-12-20 22:29:53 +08:00
return user != nil && user . SigninWrongTimes >= failedSigninLimit , nil
2023-04-22 16:16:25 +08:00
}
2023-05-30 15:49:39 +08:00
return providerItem . Rule == "Always" , nil
2022-10-28 13:38:14 +08:00
}
}
2023-05-30 15:49:39 +08:00
return false , nil
2022-10-28 13:38:14 +08:00
}