enhancement(autoprovision): Allow to configure which claims to use for auto-provisioning user accounts

When auto-provisioning user accounts we used a fixed mapping for claims
for the userinfo response to user attributes. This change introduces
configuration options to defined which claims should be user for the
username, display name and email address of the auto-provisioned
accounts.

This also removes the automatic fallback to use the 'mail' claim as the
username when the 'preferred_username' claim does not exist.

Fixes: #8635
This commit is contained in:
Ralf Haferkamp
2024-04-24 15:46:46 +02:00
parent 9035b832c0
commit 741dce501b
4 changed files with 60 additions and 41 deletions

View File

@@ -8,8 +8,8 @@ import (
"os"
"time"
"github.com/owncloud/ocis/v2/services/proxy/pkg/staticroutes"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/store"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/justinas/alice"
"github.com/oklog/run"
@@ -18,8 +18,6 @@ import (
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/store"
"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
pkgmiddleware "github.com/owncloud/ocis/v2/ocis-pkg/middleware"
@@ -39,6 +37,7 @@ import (
"github.com/owncloud/ocis/v2/services/proxy/pkg/router"
"github.com/owncloud/ocis/v2/services/proxy/pkg/server/debug"
proxyHTTP "github.com/owncloud/ocis/v2/services/proxy/pkg/server/http"
"github.com/owncloud/ocis/v2/services/proxy/pkg/staticroutes"
"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
"github.com/owncloud/ocis/v2/services/proxy/pkg/userroles"
ocisstore "github.com/owncloud/ocis/v2/services/store/pkg/store"
@@ -227,6 +226,7 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config,
backend.WithMachineAuthAPIKey(cfg.MachineAuthAPIKey),
backend.WithOIDCissuer(cfg.OIDC.Issuer),
backend.WithServiceAccount(cfg.ServiceAccount),
backend.WithAutoProvisionClaims(cfg.AutoProvisionClaims),
)
default:
logger.Fatal().Msgf("Invalid accounts backend type '%s'", cfg.AccountBackend)

View File

@@ -24,25 +24,26 @@ type Config struct {
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
GrpcClient client.Client `yaml:"-"`
RoleQuotas map[string]uint64 `yaml:"role_quotas"`
Policies []Policy `yaml:"policies"`
AdditionalPolicies []Policy `yaml:"additional_policies"`
OIDC OIDC `yaml:"oidc"`
ServiceAccount ServiceAccount `yaml:"service_account"`
RoleAssignment RoleAssignment `yaml:"role_assignment"`
PolicySelector *PolicySelector `yaml:"policy_selector"`
PreSignedURL PreSignedURL `yaml:"pre_signed_url"`
AccountBackend string `yaml:"account_backend" env:"PROXY_ACCOUNT_BACKEND_TYPE" desc:"Account backend the PROXY service should use. Currently only 'cs3' is possible here." introductionVersion:"pre5.0"`
UserOIDCClaim string `yaml:"user_oidc_claim" env:"PROXY_USER_OIDC_CLAIM" desc:"The name of an OpenID Connect claim that is used for resolving users with the account backend. The value of the claim must hold a per user unique, stable and non re-assignable identifier. The availability of claims depends on your Identity Provider. There are common claims available for most Identity providers like 'email' or 'preferred_username' but you can also add your own claim." introductionVersion:"pre5.0"`
UserCS3Claim string `yaml:"user_cs3_claim" env:"PROXY_USER_CS3_CLAIM" desc:"The name of a CS3 user attribute (claim) that should be mapped to the 'user_oidc_claim'. Supported values are 'username', 'mail' and 'userid'." introductionVersion:"pre5.0"`
MachineAuthAPIKey string `mask:"password" yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;PROXY_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary to access resources from other services." introductionVersion:"pre5.0"`
AutoprovisionAccounts bool `yaml:"auto_provision_accounts" env:"PROXY_AUTOPROVISION_ACCOUNTS" desc:"Set this to 'true' to automatically provision users that do not yet exist in the users service on-demand upon first sign-in. To use this a write-enabled libregraph user backend needs to be setup an running." introductionVersion:"pre5.0"`
EnableBasicAuth bool `yaml:"enable_basic_auth" env:"PROXY_ENABLE_BASIC_AUTH" desc:"Set this to true to enable 'basic authentication' (username/password)." introductionVersion:"pre5.0"`
InsecureBackends bool `yaml:"insecure_backends" env:"PROXY_INSECURE_BACKENDS" desc:"Disable TLS certificate validation for all HTTP backend connections." introductionVersion:"pre5.0"`
BackendHTTPSCACert string `yaml:"backend_https_cacert" env:"PROXY_HTTPS_CACERT" desc:"Path/File for the root CA certificate used to validate the servers TLS certificate for https enabled backend services." introductionVersion:"pre5.0"`
AuthMiddleware AuthMiddleware `yaml:"auth_middleware"`
PoliciesMiddleware PoliciesMiddleware `yaml:"policies_middleware"`
CSPConfigFileLocation string `yaml:"csp_config_file_location" env:"PROXY_CSP_CONFIG_FILE_LOCATION" desc:"The location of the CSP configuration file." introductionVersion:"6.0"`
RoleQuotas map[string]uint64 `yaml:"role_quotas"`
Policies []Policy `yaml:"policies"`
AdditionalPolicies []Policy `yaml:"additional_policies"`
OIDC OIDC `yaml:"oidc"`
ServiceAccount ServiceAccount `yaml:"service_account"`
RoleAssignment RoleAssignment `yaml:"role_assignment"`
PolicySelector *PolicySelector `yaml:"policy_selector"`
PreSignedURL PreSignedURL `yaml:"pre_signed_url"`
AccountBackend string `yaml:"account_backend" env:"PROXY_ACCOUNT_BACKEND_TYPE" desc:"Account backend the PROXY service should use. Currently only 'cs3' is possible here." introductionVersion:"pre5.0"`
UserOIDCClaim string `yaml:"user_oidc_claim" env:"PROXY_USER_OIDC_CLAIM" desc:"The name of an OpenID Connect claim that is used for resolving users with the account backend. The value of the claim must hold a per user unique, stable and non re-assignable identifier. The availability of claims depends on your Identity Provider. There are common claims available for most Identity providers like 'email' or 'preferred_username' but you can also add your own claim." introductionVersion:"pre5.0"`
UserCS3Claim string `yaml:"user_cs3_claim" env:"PROXY_USER_CS3_CLAIM" desc:"The name of a CS3 user attribute (claim) that should be mapped to the 'user_oidc_claim'. Supported values are 'username', 'mail' and 'userid'." introductionVersion:"pre5.0"`
MachineAuthAPIKey string `mask:"password" yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;PROXY_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary to access resources from other services." introductionVersion:"pre5.0"`
AutoprovisionAccounts bool `yaml:"auto_provision_accounts" env:"PROXY_AUTOPROVISION_ACCOUNTS" desc:"Set this to 'true' to automatically provision users that do not yet exist in the users service on-demand upon first sign-in. To use this a write-enabled libregraph user backend needs to be setup an running." introductionVersion:"pre5.0"`
AutoProvisionClaims AutoProvisionClaims `yaml:"auto_provision_claims"`
EnableBasicAuth bool `yaml:"enable_basic_auth" env:"PROXY_ENABLE_BASIC_AUTH" desc:"Set this to true to enable 'basic authentication' (username/password)." introductionVersion:"pre5.0"`
InsecureBackends bool `yaml:"insecure_backends" env:"PROXY_INSECURE_BACKENDS" desc:"Disable TLS certificate validation for all HTTP backend connections." introductionVersion:"pre5.0"`
BackendHTTPSCACert string `yaml:"backend_https_cacert" env:"PROXY_HTTPS_CACERT" desc:"Path/File for the root CA certificate used to validate the servers TLS certificate for https enabled backend services." introductionVersion:"pre5.0"`
AuthMiddleware AuthMiddleware `yaml:"auth_middleware"`
PoliciesMiddleware PoliciesMiddleware `yaml:"policies_middleware"`
CSPConfigFileLocation string `yaml:"csp_config_file_location" env:"PROXY_CSP_CONFIG_FILE_LOCATION" desc:"The location of the CSP configuration file." introductionVersion:"6.0"`
Context context.Context `yaml:"-" json:"-"`
}
@@ -153,6 +154,13 @@ type RoleMapping struct {
ClaimValue string `yaml:"claim_value" desc:"The value of the 'PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM' that matches the role defined in 'role_name'."`
}
// AutoProvisionClaims defines which claims from the OIDC userinfo response should be used for auto-provisioning user accounts
type AutoProvisionClaims struct {
Username string `yaml:"username" env:"PROXY_AUTOPROVISION_CLAIM_USERNAME" desc:"The name of the OIDC claim that holds the username." introductionVersion:"5.1"`
Email string `yaml:"email" env:"PROXY_AUTOPROVISION_CLAIM_EMAIL" desc:"The name of the OIDC claim that holds the email." introductionVersion:"5.1"`
DisplayName string `yaml:"display_name" env:"PROXY_AUTOPROVISION_CLAIM_DISPLAYNAME" desc:"The name of the OIDC claim that holds the display name." introductionVersion:"5.1"`
}
// PolicySelector is the toplevel-configuration for different selectors
type PolicySelector struct {
Static *StaticSelectorConf `yaml:"static"`

View File

@@ -84,6 +84,11 @@ func DefaultConfig() *config.Config {
UserOIDCClaim: "preferred_username",
UserCS3Claim: "username",
AutoprovisionAccounts: false,
AutoProvisionClaims: config.AutoProvisionClaims{
Username: "preferred_username",
Email: "email",
DisplayName: "name",
},
EnableBasicAuth: false,
InsecureBackends: false,
CSPConfigFileLocation: "",

View File

@@ -16,7 +16,6 @@ import (
"go-micro.dev/v4/selector"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
@@ -32,11 +31,12 @@ type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
logger log.Logger
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
machineAuthAPIKey string
oidcISS string
serviceAccount config.ServiceAccount
logger log.Logger
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
machineAuthAPIKey string
oidcISS string
serviceAccount config.ServiceAccount
autoProvisionClaims config.AutoProvisionClaims
}
// WithLogger sets the logger option
@@ -74,6 +74,12 @@ func WithServiceAccount(c config.ServiceAccount) Option {
}
}
func WithAutoProvisionClaims(claims config.AutoProvisionClaims) Option {
return func(o *Options) {
o.autoProvisionClaims = claims
}
}
// NewCS3UserBackend creates a user-provider which fetches users from a CS3 UserBackend
func NewCS3UserBackend(opts ...Option) UserBackend {
opt := Options{}
@@ -262,22 +268,22 @@ func (c cs3backend) isAlreadyExists(resp *http.Response) (bool, error) {
}
func (c cs3backend) libregraphUserFromClaims(ctx context.Context, claims map[string]interface{}) (libregraph.User, error) {
var ok bool
var dn, mail, username string
user := libregraph.User{}
if dn, ok = claims[oidc.Name].(string); !ok {
return user, fmt.Errorf("Missing claim '%s'", oidc.Name)
if dn, ok := claims[c.autoProvisionClaims.DisplayName].(string); ok {
user.SetDisplayName(dn)
} else {
return user, fmt.Errorf("Missing claim '%s' (displayName)", c.autoProvisionClaims.DisplayName)
}
if mail, ok = claims[oidc.Email].(string); !ok {
return user, fmt.Errorf("Missing claim '%s'", oidc.Email)
if mail, ok := claims[c.autoProvisionClaims.Email].(string); ok {
user.SetMail(mail)
} else {
return user, fmt.Errorf("Missing claim '%s' (mail)", c.autoProvisionClaims.Email)
}
if username, ok = claims[oidc.PreferredUsername].(string); !ok {
c.logger.Warn().Str("claim", oidc.PreferredUsername).Msg("Missing claim for username, falling back to email address")
username = mail
if username, ok := claims[c.autoProvisionClaims.Username].(string); ok {
user.SetOnPremisesSamAccountName(username)
} else {
return user, fmt.Errorf("Missing claim '%s' (username)", c.autoProvisionClaims.Username)
}
user.DisplayName = &dn
user.OnPremisesSamAccountName = &username
user.Mail = &mail
return user, nil
}