Skip to content

Commit

Permalink
support cloud industry oidc authn and userinfo
Browse files Browse the repository at this point in the history
  • Loading branch information
caryxychen committed Apr 26, 2022
1 parent 2c472e3 commit 9d65fb8
Show file tree
Hide file tree
Showing 14 changed files with 482 additions and 47 deletions.
50 changes: 40 additions & 10 deletions cmd/tke-auth-api/app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"regexp"
"strings"
"time"
"tkestack.io/tke/pkg/auth/authentication/oidc/identityprovider/cloudindustry"

"github.com/casbin/casbin/v2"
casbinlog "github.com/casbin/casbin/v2/log"
Expand Down Expand Up @@ -185,6 +186,11 @@ func CreateConfigFromOptions(serverName string, opts *options.Options) (*Config,
if err != nil {
return nil, err
}
case cloudindustry.ConnectorType:
err = setupCloudIndustryConnector(opts.Auth)
if err != nil {
return nil, err
}
default:
log.Warn("Unknown init tenant type", log.String("type", opts.Auth.InitTenantType))
}
Expand Down Expand Up @@ -362,11 +368,30 @@ func setupLDAPConnector(auth *options.AuthOptions) error {
if err != nil {
return err
}
identityprovider.SetIdentityProvider(auth.InitTenantID, idp)
return nil
}

func setupCloudIndustryConnector(auth *options.AuthOptions) error {
log.Info("setup cloud industry connector", log.Any("tenantID", auth.InitTenantID))
const errFmt = "failed to load cloud industry config file %s, error %v"
// compute absolute path based on current working dir
cloudIndustryConfigFile, err := filepath.Abs(auth.CloudIndustryConfigFile)
if err != nil {
return fmt.Errorf(errFmt, cloudIndustryConfigFile, err)
}

if _, ok := identityprovider.GetIdentityProvider(auth.InitTenantID); !ok {
identityprovider.SetIdentityProvider(auth.InitTenantID, idp)
bytes, err := ioutil.ReadFile(cloudIndustryConfigFile)
var sdkConfig cloudindustry.SDKConfig
if err := json.Unmarshal(bytes, &sdkConfig); err != nil {
return fmt.Errorf(errFmt, cloudIndustryConfigFile, err)
}

idp, err := cloudindustry.NewCloudIndustryIdentityProvider(auth.InitTenantID, auth.InitIDPAdmins, &sdkConfig)
if err != nil {
return err
}
identityprovider.SetIdentityProvider(auth.InitTenantID, idp)
return nil
}

Expand All @@ -383,20 +408,25 @@ func setupDefaultClient(store dexstorage.Storage, auth *options.AuthOptions) err
continue
}
}
cli := dexstorage.Client{
ID: auth.InitClientID,
Secret: auth.InitClientSecret,
Name: auth.InitClientID,
RedirectURIs: auth.InitClientRedirectUris,
}
if !exists {
cli := dexstorage.Client{
ID: auth.InitClientID,
Secret: auth.InitClientSecret,
Name: auth.InitClientID,
RedirectURIs: auth.InitClientRedirectUris,
}

// Create a default connector
if err = store.CreateClient(cli); err != nil && err != dexstorage.ErrAlreadyExists {
return err
}
} else {
// Update default connector
if err = store.UpdateClient(auth.InitClientID, func(old dexstorage.Client) (dexstorage.Client, error) {
return cli, nil
}); err != nil {
return err
}
}

return nil
}

Expand Down
76 changes: 45 additions & 31 deletions cmd/tke-auth-api/app/options/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package options
import (
"fmt"
"time"
"tkestack.io/tke/pkg/auth/authentication/oidc/identityprovider/cloudindustry"

"tkestack.io/tke/pkg/auth/authentication/oidc/identityprovider/ldap"
"tkestack.io/tke/pkg/auth/authentication/oidc/identityprovider/local"
Expand All @@ -30,43 +31,46 @@ import (
)

const (
flagAuthAssetsPath = "assets-path"
flagAuthIDTokenTimeout = "id-token-timeout"
flagAuthInitTenantType = "init-tenant-type"
flagAuthInitTenantID = "init-tenant-id"
flagAuthInitIDPAdmins = "init-idp-administrators"
flagAuthLDAPConfigFile = "ldap-config-file"
flagAuthInitClientID = "init-client-id"
flagAuthInitClientSecret = "init-client-secret"
flagAuthInitClientRedirectUris = "init-client-redirect-uris"
flagAuthPasswordGrantConnID = "password-grant-conn-id"
flagAuthAssetsPath = "assets-path"
flagAuthIDTokenTimeout = "id-token-timeout"
flagAuthInitTenantType = "init-tenant-type"
flagAuthInitTenantID = "init-tenant-id"
flagAuthInitIDPAdmins = "init-idp-administrators"
flagAuthLDAPConfigFile = "ldap-config-file"
flagAuthCloudIndustryConfigFile = "cloudindustry-config-file"
flagAuthInitClientID = "init-client-id"
flagAuthInitClientSecret = "init-client-secret"
flagAuthInitClientRedirectUris = "init-client-redirect-uris"
flagAuthPasswordGrantConnID = "password-grant-conn-id"
)

const (
configAuthAssetsPath = "auth.assets_path"
configAuthIDTokenTimeout = "auth.id_token_timeout"
configAuthInitTenantType = "auth.init_tenant_type"
configAuthInitTenantID = "auth.init_tenant_id"
configAuthInitIDPAdmins = "auth.init_idp_administrators"
configAuthLDAPConfigFile = "auth.ldap_config_file"
configAuthInitClientID = "auth.init_client_id"
configAuthInitClientSecret = "auth.init_client_secret"
configAuthInitClientRedirectUris = "auth.init_client_redirect_uris"
configAuthPasswordGrantConnID = "auth.password_grant_conn_id"
configAuthAssetsPath = "auth.assets_path"
configAuthIDTokenTimeout = "auth.id_token_timeout"
configAuthInitTenantType = "auth.init_tenant_type"
configAuthInitTenantID = "auth.init_tenant_id"
configAuthInitIDPAdmins = "auth.init_idp_administrators"
configAuthLDAPConfigFile = "auth.ldap_config_file"
configAuthCloudIndustryConfigFile = "auth.cloudindustry_config_file"
configAuthInitClientID = "auth.init_client_id"
configAuthInitClientSecret = "auth.init_client_secret"
configAuthInitClientRedirectUris = "auth.init_client_redirect_uris"
configAuthPasswordGrantConnID = "auth.password_grant_conn_id"
)

// AuthOptions contains configuration items related to auth attributes.
type AuthOptions struct {
AssetsPath string
IDTokenTimeout time.Duration
InitTenantType string
InitTenantID string
InitIDPAdmins []string
LdapConfigFile string
InitClientID string
InitClientSecret string
InitClientRedirectUris []string
PasswordGrantConnID string
AssetsPath string
IDTokenTimeout time.Duration
InitTenantType string
InitTenantID string
InitIDPAdmins []string
LdapConfigFile string
CloudIndustryConfigFile string
InitClientID string
InitClientSecret string
InitClientRedirectUris []string
PasswordGrantConnID string
}

// NewAuthOptions creates a AuthOptions object with default parameters.
Expand Down Expand Up @@ -102,9 +106,13 @@ func (o *AuthOptions) AddFlags(fs *pflag.FlagSet) {
_ = viper.BindPFlag(configAuthInitIDPAdmins, fs.Lookup(flagAuthInitIDPAdmins))

fs.String(flagAuthLDAPConfigFile, o.LdapConfigFile,
"Config file path for ldap ldap, must specify if init-tenant-type is ldap.")
"Config file path for ldap identity provider, must specify if init-tenant-type is ldap.")
_ = viper.BindPFlag(configAuthLDAPConfigFile, fs.Lookup(flagAuthLDAPConfigFile))

fs.String(flagAuthCloudIndustryConfigFile, o.CloudIndustryConfigFile,
"Config file path for cloud industry identity provider, must specify if init-tenant-type is cloudindustry.")
_ = viper.BindPFlag(configAuthCloudIndustryConfigFile, fs.Lookup(flagAuthCloudIndustryConfigFile))

fs.String(flagAuthInitClientID, o.InitClientID,
"Default client id will be created when started.")
_ = viper.BindPFlag(configAuthInitClientID, fs.Lookup(flagAuthInitClientID))
Expand Down Expand Up @@ -140,6 +148,12 @@ func (o *AuthOptions) ApplyFlags() []error {
if o.InitTenantType == ldap.ConnectorType && o.LdapConfigFile == "" {
errs = append(errs, fmt.Errorf("--%s must be specified for ldap type tenant", flagAuthLDAPConfigFile))
}

o.CloudIndustryConfigFile = viper.GetString(configAuthCloudIndustryConfigFile)
if o.InitTenantType == cloudindustry.ConnectorType && o.CloudIndustryConfigFile == "" {
errs = append(errs, fmt.Errorf("--%s must be specified for ldap type tenant", flagAuthCloudIndustryConfigFile))
}

o.InitTenantID = viper.GetString(configAuthInitTenantID)
if len(o.InitTenantID) == 0 {
errs = append(errs, fmt.Errorf("--%s must be specified", flagAuthInitTenantID))
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/aws/aws-sdk-go v1.40.37
github.com/bitly/go-simplejson v0.5.0
github.com/caddyserver/caddy v1.0.5
github.com/caryxychen/cloudindustry-sdk-go v1.0.0
github.com/casbin/casbin/v2 v2.2.1
github.com/chartmuseum/helm-push v0.9.0
github.com/chartmuseum/storage v0.11.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k
github.com/caddyserver/caddy v1.0.5 h1:5B1Hs0UF2x2tggr2X9jL2qOZtDXbIWQb9YLbmlxHSuM=
github.com/caddyserver/caddy v1.0.5/go.mod h1:AnFHB+/MrgRC+mJAvuAgQ38ePzw+wKeW0wzENpdQQKY=
github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
github.com/caryxychen/cloudindustry-sdk-go v1.0.0 h1:bsdS6BP49K+VCzHbsa+hUEmOfryXuDpxdFrA24Z67vo=
github.com/caryxychen/cloudindustry-sdk-go v1.0.0/go.mod h1:ZqQXwtco2MGa2s6MAP6snl5bg/M+0rufb7E8zDuCn1M=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/casbin/casbin/v2 v2.2.1 h1:ijrSMfBfbQlDc4LnMTGtGYWmhKuuR6RLSQRj8vHrMzc=
github.com/casbin/casbin/v2 v2.2.1/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
Expand Down
19 changes: 19 additions & 0 deletions pkg/apiserver/authentication/authenticator/oidc/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,25 @@ type ProviderJSON struct {
UserInfoURL string `json:"userinfo_endpoint"`
}

// staticKeySet implements oidc.KeySet.
type staticKeySet struct {}

func parseJWT(p string) ([]byte, error) {
parts := strings.Split(p, ".")
if len(parts) < 2 {
return nil, fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts))
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt payload: %v", err)
}
return payload, nil
}

func (s *staticKeySet) VerifySignature(ctx context.Context, jwt string) (payload []byte, err error) {
return parseJWT(jwt)
}

// NewIDTokenVerifier uses the OpenID Connect discovery mechanism to construct a verifier manually from a issuer URL.
// The issuer is the URL identifier for the service. For example: "https://accounts.google.com"
// or "https://login.salesforce.com".
Expand Down
4 changes: 3 additions & 1 deletion pkg/auth/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"fmt"
"net/http"
"time"
"tkestack.io/tke/pkg/auth/authentication/oidc/identityprovider/cloudindustry"

"tkestack.io/tke/api/auth"
"tkestack.io/tke/pkg/auth/authentication/oidc/identityprovider"
Expand Down Expand Up @@ -228,11 +229,12 @@ func (c completedConfig) registerHooks(dexHandler *identityprovider.DexHander, s

localIdpHook := local.NewLocalHookHandler(authClient)
ldapIdpHook := ldap.NewLdapHookHandler(authClient)
cloudIndustryIdpHook := cloudindustry.NewCloudIndustryHookHandler(authClient)

authVersionedClient := versionedclientset.NewForConfigOrDie(s.LoopbackClientConfig)
adapterHook := local2.NewAdapterHookHandler(authVersionedClient, c.ExtraConfig.CasbinEnforcer, c.ExtraConfig.VersionedInformers, c.ExtraConfig.CasbinReloadInterval)

return []genericapiserver.PostStartHookProvider{dexHook, apiSigningKeyHook, localIdpHook, ldapIdpHook, adapterHook}
return []genericapiserver.PostStartHookProvider{dexHook, apiSigningKeyHook, localIdpHook, ldapIdpHook, cloudIndustryIdpHook, adapterHook}
}

// installCasbinPreStopHook is used to register preStop hook to stop casbin enforcer sync.
Expand Down
2 changes: 2 additions & 0 deletions pkg/auth/authentication/oidc/claims/claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type IDTokenClaims struct {

// FederatedIDClaims represents the extension struct of claims.
type FederatedIDClaims struct {
// 租户ID
ConnectorID string `json:"connector_id,omitempty"`
// 用户ID
UserID string `json:"user_id,omitempty"`
}
Loading

0 comments on commit 9d65fb8

Please sign in to comment.