Skip to content
Closed

1 #4026

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ RUN apk add --no-cache \
# This ensures version consistency between backup tools and the database server
COPY --from=pg-client /usr/local/bin/pg_dump /usr/local/bin/pg_dump
COPY --from=pg-client /usr/local/bin/psql /usr/local/bin/psql
COPY --from=pg-client /usr/local/bin/pg_restore /usr/local/bin/pg_restore
COPY --from=pg-client /usr/local/lib/libpq.so.5* /usr/local/lib/

# Create non-root user
Expand Down
11 changes: 7 additions & 4 deletions backend/cmd/server/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/ent/schema/auth_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var authProviderTypes = map[string]struct{}{
"oidc": {},
"wechat": {},
"dingtalk": {},
"feishu": {},
}

func validateAuthProviderType(value string) error {
Expand Down
6 changes: 5 additions & 1 deletion backend/ent/schema/auth_identity_schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ func TestAuthIdentityFoundationSchemas(t *testing.T) {
"metadata",
)
requireHasUniqueIndex(t, authIdentity, "provider_type", "provider_key", "provider_subject")
for _, value := range []string{"email", "github", "google", "linuxdo", "oidc", "wechat", "dingtalk", "feishu"} {
require.NoError(t, validateAuthProviderType(value))
}
require.Error(t, validateAuthProviderType("unknown"))

authIdentityChannel := requireSchema(t, schemas, "AuthIdentityChannel")
requireSchemaFields(t, authIdentityChannel,
Expand Down Expand Up @@ -83,7 +87,7 @@ func TestAuthIdentityFoundationSchemas(t *testing.T) {
require.Equal(t, 1, signupSource.Validators)

validator := requireStringFieldValidator(t, User{}.Fields(), "signup_source")
for _, value := range []string{"email", "linuxdo", "wechat", "oidc", "github", "google", "dingtalk"} {
for _, value := range []string{"email", "linuxdo", "wechat", "oidc", "github", "google", "dingtalk", "feishu"} {
require.NoError(t, validator(value))
}
require.Error(t, validator("unknown"))
Expand Down
4 changes: 2 additions & 2 deletions backend/ent/schema/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ func (User) Fields() []ent.Field {
field.String("signup_source").
Validate(func(value string) error {
switch value {
case "email", "linuxdo", "wechat", "oidc", "github", "google", "dingtalk":
case "email", "linuxdo", "wechat", "oidc", "github", "google", "dingtalk", "feishu":
return nil
default:
return fmt.Errorf("must be one of email, linuxdo, wechat, oidc, github, google, dingtalk")
return fmt.Errorf("must be one of email, linuxdo, wechat, oidc, github, google, dingtalk, feishu")
}
}).
Default("email"),
Expand Down
50 changes: 50 additions & 0 deletions backend/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type Config struct {
WeChat WeChatConnectConfig `mapstructure:"wechat_connect"`
OIDC OIDCConnectConfig `mapstructure:"oidc_connect"`
DingTalk DingTalkConnectConfig `mapstructure:"dingtalk_connect"`
Feishu FeishuConnectConfig `mapstructure:"feishu_connect"`
GitHubOAuth EmailOAuthProviderConfig `mapstructure:"github_oauth"`
GoogleOAuth EmailOAuthProviderConfig `mapstructure:"google_oauth"`
Default DefaultConfig `mapstructure:"default"`
Expand Down Expand Up @@ -285,6 +286,29 @@ type DingTalkConnectConfig struct {
AttributeSyncOverwritePolicy string `mapstructure:"attribute_sync_overwrite_policy"`
}

type FeishuConnectConfig struct {
Enabled bool `mapstructure:"enabled"`
AppID string `mapstructure:"app_id"`
AppSecret string `mapstructure:"app_secret"`
AuthorizeURL string `mapstructure:"authorize_url"`
TokenURL string `mapstructure:"token_url"`
UserInfoURL string `mapstructure:"userinfo_url"`
Scopes string `mapstructure:"scopes"`
RedirectURL string `mapstructure:"redirect_url"`
FrontendRedirectURL string `mapstructure:"frontend_redirect_url"`

TenantRestrictionPolicy string `mapstructure:"tenant_restriction_policy"` // none | internal_only
AllowedTenantKey string `mapstructure:"allowed_tenant_key"`
BypassRegistration bool `mapstructure:"bypass_registration"`
SyncEmail bool `mapstructure:"sync_email"`
SyncDisplayName bool `mapstructure:"sync_display_name"`
SyncDepartment bool `mapstructure:"sync_department"`
OrgSyncEnabled bool `mapstructure:"org_sync_enabled"`
DepartedUserAction string `mapstructure:"departed_user_action"` // auto_disable
DisableThresholdCount int `mapstructure:"sync_disable_threshold_count"`
DisableThresholdPercent int `mapstructure:"sync_disable_threshold_percent"`
}

type EmailOAuthProviderConfig struct {
Enabled bool `mapstructure:"enabled"`
ClientID string `mapstructure:"client_id"`
Expand All @@ -302,6 +326,11 @@ const (
defaultWeChatConnectMode = "open"
defaultWeChatConnectScopes = "snsapi_login"
defaultWeChatConnectFrontendRedirect = "/auth/wechat/callback"
defaultFeishuConnectAuthorizeURL = "https://accounts.feishu.cn/open-apis/authen/v1/authorize"
defaultFeishuConnectTokenURL = "https://accounts.feishu.cn/oauth/v3/token"
defaultFeishuConnectUserInfoURL = "https://open.feishu.cn/open-apis/authen/v1/user_info"
defaultFeishuConnectScopes = "contact:user.base:readonly contact:user.email:readonly contact:user.employee_id:readonly"
defaultFeishuConnectFrontendRedirect = "/auth/feishu/callback"
)

func firstNonEmptyString(values ...string) string {
Expand Down Expand Up @@ -1702,6 +1731,27 @@ func setDefaults() {
viper.SetDefault("dingtalk_connect.require_email", true)
viper.SetDefault("dingtalk_connect.username_overwrite_policy", "if_empty")

// Feishu Connect OAuth 登录
viper.SetDefault("feishu_connect.enabled", false)
viper.SetDefault("feishu_connect.app_id", "")
viper.SetDefault("feishu_connect.app_secret", "")
viper.SetDefault("feishu_connect.authorize_url", defaultFeishuConnectAuthorizeURL)
viper.SetDefault("feishu_connect.token_url", defaultFeishuConnectTokenURL)
viper.SetDefault("feishu_connect.userinfo_url", defaultFeishuConnectUserInfoURL)
viper.SetDefault("feishu_connect.scopes", defaultFeishuConnectScopes)
viper.SetDefault("feishu_connect.redirect_url", "")
viper.SetDefault("feishu_connect.frontend_redirect_url", defaultFeishuConnectFrontendRedirect)
viper.SetDefault("feishu_connect.tenant_restriction_policy", "internal_only")
viper.SetDefault("feishu_connect.allowed_tenant_key", "")
viper.SetDefault("feishu_connect.bypass_registration", false)
viper.SetDefault("feishu_connect.sync_email", true)
viper.SetDefault("feishu_connect.sync_display_name", true)
viper.SetDefault("feishu_connect.sync_department", true)
viper.SetDefault("feishu_connect.org_sync_enabled", false)
viper.SetDefault("feishu_connect.departed_user_action", "auto_disable")
viper.SetDefault("feishu_connect.sync_disable_threshold_count", 10)
viper.SetDefault("feishu_connect.sync_disable_threshold_percent", 20)

// Database
viper.SetDefault("database.host", "localhost")
viper.SetDefault("database.port", 5432)
Expand Down
Loading
Loading