ugly working draft

This commit is contained in:
A.Unger
2020-12-02 15:31:17 +01:00
parent 752cd4f626
commit 2910e88ba5
9 changed files with 81 additions and 16 deletions
+2
View File
@@ -42,6 +42,7 @@ func Authentication(opts ...Option) func(next http.Handler) http.Handler {
OIDCIss(options.OIDCIss),
TokenCacheSize(options.UserinfoCacheSize),
TokenCacheTTL(time.Second*time.Duration(options.UserinfoCacheTTL)),
CredentialsByUserAgent(options.CredentialsByUserAgent),
)
basic := BasicAuth(
@@ -49,6 +50,7 @@ func Authentication(opts ...Option) func(next http.Handler) http.Handler {
EnableBasicAuth(options.EnableBasicAuth),
AccountsClient(options.AccountsClient),
OIDCIss(options.OIDCIss),
CredentialsByUserAgent(options.CredentialsByUserAgent),
)
return func(next http.Handler) http.Handler {
+29 -3
View File
@@ -37,21 +37,47 @@ func BasicAuth(optionSetters ...Option) func(next http.Handler) http.Handler {
if !h.isPublicLink(req) {
for i := 0; i < len(ProxyWwwAuthenticate); i++ {
if strings.Contains(req.RequestURI, fmt.Sprintf("/%v/", ProxyWwwAuthenticate[i])) {
for k, v := range options.CredentialsByUserAgent {
if strings.Contains(k, req.UserAgent()) {
w.Header().Del("Www-Authenticate")
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host))
goto OUT
}
}
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", "Basic", req.Host))
}
}
}
OUT:
next.ServeHTTP(w, req)
return
}
w.Header().Del("Www-Authenticate")
account, ok := h.getAccount(req)
// touch is a user agent locking guard, when touched changes to true it indicates the User-Agent on the
// request is configured to support only one challenge, it it remains untouched, there are no considera-
// tions and we should write all available authentication challenges to the response.
touch := false
if !ok {
for i := 0; i < len(ProxyWwwAuthenticate); i++ {
if strings.Contains(req.RequestURI, fmt.Sprintf("/%v/", ProxyWwwAuthenticate[i])) {
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", "Basic", req.Host))
// if the request is bound to a user agent the locked write Www-Authenticate for such user
for k, v := range options.CredentialsByUserAgent {
if strings.Contains(k, req.UserAgent()) {
w.Header().Del("Www-Authenticate")
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host))
touch = true
break
}
}
// if the request is not bound to any user agent, write all available challenges
if !touch {
writeSupportedAuthenticateHeader(w, req)
}
w.WriteHeader(http.StatusUnauthorized)
return
}
+8 -7
View File
@@ -41,18 +41,19 @@ func OIDCAuth(optionSetters ...Option) func(next http.Handler) http.Handler {
// there is no bearer token on the request,
if !h.shouldServe(req) {
// oidc supported but token not present, add header and handover to the next middleware.
// TODO for this logic to work and we don't return superfluous Www-Authenticate headers we would need to
// add Www-Authenticate only on selected endpoints, because Reva won't cleanup already written headers.
// this means that requests such as:
// curl -v -k -u admin:admin -H "depth: 0" -X PROPFIND https://localhost:9200/remote.php/dav/files | xmllint --format -
// even when succeeding, will contain a Www-Authenticate header.
for i := 0; i < len(ProxyWwwAuthenticate); i++ {
if strings.Contains(req.RequestURI, fmt.Sprintf("/%v/", ProxyWwwAuthenticate[i])) {
for k, v := range options.CredentialsByUserAgent {
if strings.Contains(k, req.UserAgent()) {
w.Header().Del("Www-Authenticate")
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", strings.Title(v), req.Host))
goto OUT
}
}
w.Header().Add("Www-Authenticate", fmt.Sprintf("%v realm=\"%s\", charset=\"UTF-8\"", "Bearer", req.Host))
}
}
OUT:
next.ServeHTTP(w, req)
return
}
+9
View File
@@ -46,6 +46,8 @@ type Options struct {
UserinfoCacheSize int
// UserinfoCacheTTL sets the max cache duration for the userinfo cache, intended for the oidc_auth middleware
UserinfoCacheTTL time.Duration
// CredentialsByUserAgent sets the auth challenges on a per user-agent basis
CredentialsByUserAgent map[string]string
}
// newOptions initializes the available default options.
@@ -108,6 +110,13 @@ func OIDCIss(iss string) Option {
}
}
// CredentialsByUserAgent sets UserAgentChallenges.
func CredentialsByUserAgent(v map[string]string) Option {
return func(o *Options) {
o.CredentialsByUserAgent = v
}
}
// RevaGatewayClient provides a function to set the the reva gateway service client option.
func RevaGatewayClient(gc gateway.GatewayAPIClient) Option {
return func(o *Options) {