Files
opencloud/ocis-pkg/middleware/oidc.go
Jörn Friedrich Dreyer 2c98d3246c minimal webfinger (#5373)
* initial webfinger stub

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* add webfinger to proxy, return current host

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* some cleanup

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* allow passing multiple rel params

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* introduce interfaces

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* parse oidc auth token

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* add templating, drop chain, use map of relation providers

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* fix ocis url yaml

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* fix typos

Co-authored-by: Dominik Schmidt <dschmidt@owncloud.com>

* switch to userinfo claims

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* readme cleanup

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* add TODO.md with ideas

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* replace subject on authenticated request responses

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* Apply suggestions from code review

Co-authored-by: Martin <github@diemattels.at>

* markdown lint

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* return a 401 when bearer token expired, some more docs

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* Apply suggestions from code review

Co-authored-by: Martin <github@diemattels.at>

* fix docs

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* clarify env var

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* extract handler func

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* use correct service in reflex.conf

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* test relations

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* Update services/webfinger/pkg/config/config.go

---------

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
Co-authored-by: Dominik Schmidt <dschmidt@owncloud.com>
Co-authored-by: Martin <github@diemattels.at>
2023-02-13 11:05:20 +01:00

94 lines
2.2 KiB
Go

package middleware
import (
"context"
"net/http"
"strings"
"sync"
gOidc "github.com/coreos/go-oidc/v3/oidc"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
"golang.org/x/oauth2"
)
// newOidcOptions initializes the available default options.
func newOidcOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// OIDCProvider used to mock the oidc provider during tests
type OIDCProvider interface {
UserInfo(ctx context.Context, ts oauth2.TokenSource) (*gOidc.UserInfo, error)
}
// OidcAuth provides a middleware to authenticate a bearer auth with an OpenID Connect identity provider
// It will put all claims provided by the userinfo endpoint in the context
func OidcAuth(opts ...Option) func(http.Handler) http.Handler {
opt := newOidcOptions(opts...)
// TODO use a micro store cache option
providerFunc := func() (OIDCProvider, error) {
// Initialize a provider by specifying the issuer URL.
// it will fetch the keys from the issuer using the .well-known
// endpoint
return gOidc.NewProvider(
context.WithValue(context.Background(), oauth2.HTTPClient, http.Client{}),
opt.OidcIssuer,
)
}
var provider OIDCProvider
getProviderOnce := sync.Once{}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
authHeader := r.Header.Get("Authorization")
switch {
case strings.HasPrefix(authHeader, "Bearer "):
getProviderOnce.Do(func() {
var err error
provider, err = providerFunc()
if err != nil {
return
}
})
oauth2Token := &oauth2.Token{
AccessToken: strings.TrimPrefix(authHeader, "Bearer "),
}
userInfo, err := provider.UserInfo(
context.WithValue(ctx, oauth2.HTTPClient, http.Client{}),
oauth2.StaticTokenSource(oauth2Token),
)
if err != nil {
w.Header().Add("WWW-Authenticate", `Bearer`)
w.WriteHeader(http.StatusUnauthorized)
return
}
claims := map[string]interface{}{}
err = userInfo.Claims(&claims)
if err != nil {
break
}
ctx = oidc.NewContext(ctx, claims)
default:
// do nothing
next.ServeHTTP(w, r.WithContext(ctx))
return
}
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}