Merge pull request #627 from butonic/add-basic-auth-option

add enable basic auth option and check permissions
This commit is contained in:
Jörn Friedrich Dreyer
2020-11-05 16:36:16 +01:00
committed by GitHub
50 changed files with 1530 additions and 2286 deletions

View File

@@ -0,0 +1,6 @@
Enhancement: Add basic auth option
We added a new `enable-basic-auth` option and `PROXY_ENABLE_BASIC_AUTH` environment variable that can be set to `true` to make the proxy verify the basic auth header with the accounts service. This should only be used for testing and development and is disabled by default.
https://github.com/owncloud/ocis/pull/627
https://github.com/owncloud/product/issues/198

File diff suppressed because it is too large Load Diff

View File

@@ -263,6 +263,8 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic
middleware.AccountsClient(accounts),
middleware.SettingsRoleService(roles),
middleware.AutoprovisionAccounts(cfg.AutoprovisionAccounts),
middleware.EnableBasicAuth(cfg.EnableBasicAuth),
middleware.OIDCIss(cfg.OIDC.Issuer),
)
// the connection will be established in a non blocking fashion

View File

@@ -99,6 +99,7 @@ type Config struct {
Reva Reva
PreSignedURL PreSignedURL
AutoprovisionAccounts bool
EnableBasicAuth bool
}
// OIDC is the config for the OpenID-Connect middleware. If set the proxy will try to authenticate every request

View File

@@ -219,6 +219,15 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
Usage: "--presignedurl-allow-method GET [--presignedurl-allow-method POST]",
EnvVars: []string{"PRESIGNEDURL_ALLOWED_METHODS"},
},
// Basic auth
&cli.BoolFlag{
Name: "enable-basic-auth",
Value: false,
Usage: "enable basic authentication",
EnvVars: []string{"PROXY_ENABLE_BASIC_AUTH"},
Destination: &cfg.EnableBasicAuth,
},
}
}

View File

@@ -72,6 +72,8 @@ func createAccount(l log.Logger, claims *oidc.StandardClaims, ac acc.AccountsSer
func AccountUUID(opts ...Option) func(next http.Handler) http.Handler {
opt := newOptions(opts...)
publicFilesEndpoint := "/remote.php/dav/public-files/"
return func(next http.Handler) http.Handler {
// TODO: handle error
tokenManager, err := jwt.New(map[string]interface{}{
@@ -85,22 +87,43 @@ func AccountUUID(opts ...Option) func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
l := opt.Logger
claims := oidc.FromContext(r.Context())
if claims == nil {
next.ServeHTTP(w, r)
return
}
var account *acc.Account
var status int
if claims.Email != "" {
switch {
case claims == nil:
login, password, ok := r.BasicAuth()
// check if we are dealing with a public link
if ok && login == "public" && strings.HasPrefix(r.URL.Path, publicFilesEndpoint) {
// forward to reva frontend
next.ServeHTTP(w, r)
return
}
if opt.EnableBasicAuth && ok {
l.Warn().Msg("basic auth enabled, use only for testing or development")
account, status = getAccount(l, opt.AccountsClient, fmt.Sprintf("login eq '%s' and password eq '%s'", strings.ReplaceAll(login, "'", "''"), strings.ReplaceAll(password, "'", "''")))
if status == 0 {
// fake claims for the subsequent code flow
claims = &oidc.StandardClaims{
Iss: opt.OIDCIss,
}
} else {
// tell client to reauthenticate
w.WriteHeader(http.StatusUnauthorized)
return
}
} else {
next.ServeHTTP(w, r)
return
}
case claims.Email != "":
account, status = getAccount(l, opt.AccountsClient, fmt.Sprintf("mail eq '%s'", strings.ReplaceAll(claims.Email, "'", "''")))
} else if claims.PreferredUsername != "" {
case claims.PreferredUsername != "":
account, status = getAccount(l, opt.AccountsClient, fmt.Sprintf("preferred_name eq '%s'", strings.ReplaceAll(claims.PreferredUsername, "'", "''")))
} else if claims.OcisID != "" {
case claims.OcisID != "":
account, status = getAccount(l, opt.AccountsClient, fmt.Sprintf("id eq '%s'", strings.ReplaceAll(claims.OcisID, "'", "''")))
} else {
default:
// TODO allow lookup by custom claim, eg an id ... or sub
l.Error().Err(err).Msgf("Could not lookup account, no mail or preferred_username claim set")
l.Error().Err(err).Msg("Could not lookup account, no mail or preferred_username claim set")
w.WriteHeader(http.StatusInternalServerError)
}
if status != 0 || account == nil {

View File

@@ -39,6 +39,8 @@ type Options struct {
PreSignedURLConfig config.PreSignedURL
// AutoprovisionAccounts when an account does not exist.
AutoprovisionAccounts bool
// EnableBasicAuth to allow basic auth
EnableBasicAuth bool
}
// newOptions initializes the available default options.
@@ -128,3 +130,10 @@ func AutoprovisionAccounts(val bool) Option {
o.AutoprovisionAccounts = val
}
}
// EnableBasicAuth provides a function to set the EnableBasicAuth config
func EnableBasicAuth(enableBasicAuth bool) Option {
return func(o *Options) {
o.EnableBasicAuth = enableBasicAuth
}
}

View File

@@ -261,7 +261,7 @@ func defaultPolicies() []config.Policy {
},
{
Type: config.RegexRoute,
Endpoint: "/ocs/v[12].php/cloud/user", // we have `user` and `users` in ocis-ocs
Endpoint: "/ocs/v[12].php/cloud/(users?|groups)", // we have `user`, `users` and `groups` in ocis-ocs
Backend: "http://localhost:9110",
},
{

View File

@@ -145,6 +145,9 @@ func TestProxyIntegration(t *testing.T) {
if err != nil {
t.Fatal("Error reading result body")
}
if err = rr.Result().Body.Close(); err != nil {
t.Fatal("Error closing result body")
}
bodyString := string(resultBody)
if bodyString != `OK` {