mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-03 17:29:22 -05:00
refactor authentication.go
This commit is contained in:
@@ -8,42 +8,35 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SupportedAuthStrategies stores configured challenges.
|
||||
var SupportedAuthStrategies []string
|
||||
var (
|
||||
// SupportedAuthStrategies stores configured challenges.
|
||||
SupportedAuthStrategies []string
|
||||
|
||||
// ProxyWwwAuthenticate is a list of endpoints that do not rely on reva underlying authentication, such as ocs.
|
||||
// services that fallback to reva authentication are declared in the "frontend" command on OCIS. It is a list of strings
|
||||
// to be regexp compiled.
|
||||
var ProxyWwwAuthenticate = []string{"/ocs/v[12].php/cloud/"}
|
||||
// ProxyWwwAuthenticate is a list of endpoints that do not rely on reva underlying authentication, such as ocs.
|
||||
// services that fallback to reva authentication are declared in the "frontend" command on OCIS. It is a list of strings
|
||||
// to be regexp compiled.
|
||||
ProxyWwwAuthenticate = []string{"/ocs/v[12].php/cloud/"}
|
||||
|
||||
// WWWAuthenticate captures the Www-Authenticate header string.
|
||||
WWWAuthenticate = "Www-Authenticate"
|
||||
)
|
||||
|
||||
// userAgentLocker aids in dependency injection for helper methods. The set of fields is arbitrary and the only relation
|
||||
// they share is to fulfill their duty and lock a User-Agent to its correct challenge if configured.
|
||||
type userAgentLocker struct {
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
locks map[string]string // locks represents a reva user-agent:challenge mapping.
|
||||
fallback string
|
||||
}
|
||||
|
||||
// Authentication is a higher order authentication middleware.
|
||||
func Authentication(opts ...Option) func(next http.Handler) http.Handler {
|
||||
options := newOptions(opts...)
|
||||
if options.OIDCIss != "" {
|
||||
SupportedAuthStrategies = append(SupportedAuthStrategies, "bearer")
|
||||
}
|
||||
|
||||
if options.EnableBasicAuth {
|
||||
SupportedAuthStrategies = append(SupportedAuthStrategies, "basic")
|
||||
}
|
||||
|
||||
oidc := OIDCAuth(
|
||||
Logger(options.Logger),
|
||||
OIDCProviderFunc(options.OIDCProviderFunc),
|
||||
HTTPClient(options.HTTPClient),
|
||||
OIDCIss(options.OIDCIss),
|
||||
TokenCacheSize(options.UserinfoCacheSize),
|
||||
TokenCacheTTL(time.Second*time.Duration(options.UserinfoCacheTTL)),
|
||||
CredentialsByUserAgent(options.CredentialsByUserAgent),
|
||||
)
|
||||
|
||||
basic := BasicAuth(
|
||||
Logger(options.Logger),
|
||||
EnableBasicAuth(options.EnableBasicAuth),
|
||||
AccountsClient(options.AccountsClient),
|
||||
OIDCIss(options.OIDCIss),
|
||||
CredentialsByUserAgent(options.CredentialsByUserAgent),
|
||||
)
|
||||
configureSupportedChallenges(options)
|
||||
oidc := newOIDCAuth(options)
|
||||
basic := newBasicAuth(options)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -62,34 +55,77 @@ func Authentication(opts ...Option) func(next http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// configureSupportedChallenges adds known authentication challenges to the current session.
|
||||
func configureSupportedChallenges(options Options) {
|
||||
if options.OIDCIss != "" {
|
||||
SupportedAuthStrategies = append(SupportedAuthStrategies, "bearer")
|
||||
}
|
||||
|
||||
if options.EnableBasicAuth {
|
||||
SupportedAuthStrategies = append(SupportedAuthStrategies, "basic")
|
||||
}
|
||||
}
|
||||
|
||||
func writeSupportedAuthenticateHeader(w http.ResponseWriter, r *http.Request) {
|
||||
for i := 0; i < len(SupportedAuthStrategies); i++ {
|
||||
w.Header().Add("WWW-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(SupportedAuthStrategies[i]), r.Host))
|
||||
w.Header().Add(WWWAuthenticate, fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(SupportedAuthStrategies[i]), r.Host))
|
||||
}
|
||||
}
|
||||
|
||||
func removeSuperfluousAuthenticate(w http.ResponseWriter) {
|
||||
w.Header().Del("Www-Authenticate")
|
||||
w.Header().Del(WWWAuthenticate)
|
||||
}
|
||||
|
||||
// userAgentAuthenticateLockIn sets Www-Authenticate according to configured user agents. This is useful for the case of
|
||||
// legacy clients that do not support protocols like OIDC or OAuth and want to lock a given user agent to a challenge
|
||||
// such as basic. For more context check https://github.com/cs3org/reva/pull/1350
|
||||
func userAgentAuthenticateLockIn(w http.ResponseWriter, req *http.Request, creds map[string]string, fallback string) {
|
||||
func userAgentAuthenticateLockIn(w http.ResponseWriter, r *http.Request, locks map[string]string, fallback string) {
|
||||
u := userAgentLocker{
|
||||
w: w,
|
||||
r: r,
|
||||
locks: locks,
|
||||
fallback: fallback,
|
||||
}
|
||||
|
||||
for i := 0; i < len(ProxyWwwAuthenticate); i++ {
|
||||
if r, err := regexp.Compile(ProxyWwwAuthenticate[i]); err == nil {
|
||||
if r.Match([]byte(req.RequestURI)) {
|
||||
for k, v := range creds {
|
||||
if strings.Contains(k, req.UserAgent()) {
|
||||
removeSuperfluousAuthenticate(w)
|
||||
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host))
|
||||
return
|
||||
}
|
||||
}
|
||||
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(fallback), req.Host))
|
||||
}
|
||||
} else {
|
||||
// deal with err
|
||||
}
|
||||
evalRequestURI(&u, i)
|
||||
}
|
||||
}
|
||||
|
||||
func evalRequestURI(l *userAgentLocker, i int) {
|
||||
r := regexp.MustCompile(ProxyWwwAuthenticate[i])
|
||||
if r.Match([]byte(l.r.RequestURI)) {
|
||||
for k, v := range l.locks {
|
||||
if strings.Contains(k, l.r.UserAgent()) {
|
||||
removeSuperfluousAuthenticate(l.w)
|
||||
l.w.Header().Add(WWWAuthenticate, fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), l.r.Host))
|
||||
return
|
||||
}
|
||||
}
|
||||
l.w.Header().Add(WWWAuthenticate, fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(l.fallback), l.r.Host))
|
||||
}
|
||||
}
|
||||
|
||||
// newOIDCAuth returns a configured oidc middleware
|
||||
func newOIDCAuth(options Options) func(http.Handler) http.Handler {
|
||||
return OIDCAuth(
|
||||
Logger(options.Logger),
|
||||
OIDCProviderFunc(options.OIDCProviderFunc),
|
||||
HTTPClient(options.HTTPClient),
|
||||
OIDCIss(options.OIDCIss),
|
||||
TokenCacheSize(options.UserinfoCacheSize),
|
||||
TokenCacheTTL(time.Second*time.Duration(options.UserinfoCacheTTL)),
|
||||
CredentialsByUserAgent(options.CredentialsByUserAgent),
|
||||
)
|
||||
}
|
||||
|
||||
// newBasicAuth returns a configured oidc middleware
|
||||
func newBasicAuth(options Options) func(http.Handler) http.Handler {
|
||||
return BasicAuth(
|
||||
Logger(options.Logger),
|
||||
EnableBasicAuth(options.EnableBasicAuth),
|
||||
AccountsClient(options.AccountsClient),
|
||||
OIDCIss(options.OIDCIss),
|
||||
CredentialsByUserAgent(options.CredentialsByUserAgent),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user