Integrate OpenID Connect middleware

This commit is contained in:
Thomas Müller
2019-12-10 14:48:28 +01:00
parent f66b9c3624
commit d2b35e5875
8 changed files with 77 additions and 34 deletions

4
go.mod
View File

@@ -9,12 +9,14 @@ require (
github.com/cespare/reflex v0.2.0 // indirect
github.com/go-chi/chi v4.0.2+incompatible
github.com/go-chi/render v1.0.1
github.com/haya14busa/goverage v0.0.0-20180129164344-eec3514a20b5 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/micro/cli v0.2.0
github.com/ogier/pflag v0.0.1 // indirect
github.com/oklog/run v1.0.0
github.com/openzipkin/zipkin-go v0.2.2
github.com/owncloud/ocis-pkg v1.1.0
github.com/owncloud/ocis-pkg v1.2.1-0.20191216110718-ef1320072cd7
github.com/restic/calens v0.1.0 // indirect
github.com/spf13/viper v1.5.0
github.com/yaegashi/msgraph.go v0.0.0-20191104022859-3f9096c750b2
go.opencensus.io v0.22.2

15
go.sum
View File

@@ -145,6 +145,8 @@ github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.17+incompatible h1:f/Z3EoDSx1yjaIjLQGo1diYUlQYSBrrAQ5vP8NjwXwo=
github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@@ -520,6 +522,15 @@ github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukw
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
github.com/owncloud/ocis-pkg v1.1.0 h1:cwhzqQAHLA8fz94YKdmqSJguSCswx5TBNkgLAU8DbJI=
github.com/owncloud/ocis-pkg v1.1.0/go.mod h1:EfbeXoe60Me2lB/AWjYl8UFNv4isqCPP6lokd5R7nyM=
github.com/owncloud/ocis-pkg v1.2.0 h1:eP0AOSEXAgiblL2yOpNOmriKhDXN+mai+4belBJRkWU=
github.com/owncloud/ocis-pkg v1.2.1-0.20191210134105-b9281c88fa4e h1:/ZEn35TnY4Xv7VKRN43Tb5NVgt6CeYPMw5akFKB01u4=
github.com/owncloud/ocis-pkg v1.2.1-0.20191210134105-b9281c88fa4e/go.mod h1:YbsEi4rWRqnDpN1U8MDJ6Ys+cWn2lskTYgyKgOmCrFk=
github.com/owncloud/ocis-pkg v1.2.1-0.20191211143857-ab52855478bf h1:1uKK2HSeEtvK2CshhwAMFIzJLTTyd0rh2f90n3rqTqw=
github.com/owncloud/ocis-pkg v1.2.1-0.20191211143857-ab52855478bf/go.mod h1:YbsEi4rWRqnDpN1U8MDJ6Ys+cWn2lskTYgyKgOmCrFk=
github.com/owncloud/ocis-pkg v1.2.1-0.20191216100329-ca11e16505c6 h1:3kKO/aMzV+2aIYBvBgbzCuciUZxiYV7QxR9s525B9Dw=
github.com/owncloud/ocis-pkg v1.2.1-0.20191216100329-ca11e16505c6/go.mod h1:YbsEi4rWRqnDpN1U8MDJ6Ys+cWn2lskTYgyKgOmCrFk=
github.com/owncloud/ocis-pkg v1.2.1-0.20191216110718-ef1320072cd7 h1:aLFn8VM6u/2TOy6JEMP1D/09ceNr0isZ3LhegSmLVns=
github.com/owncloud/ocis-pkg v1.2.1-0.20191216110718-ef1320072cd7/go.mod h1:YbsEi4rWRqnDpN1U8MDJ6Ys+cWn2lskTYgyKgOmCrFk=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -540,6 +551,8 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@@ -754,6 +767,7 @@ golang.org/x/net v0.0.0-20191109021931-daa7c04131f5/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -906,6 +920,7 @@ gopkg.in/olivere/elastic.v5 v5.0.82/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0F
gopkg.in/redis.v3 v3.6.4/go.mod h1:6XeGv/CrsUFDU9aVbUdNykN7k1zVmoeg83KC9RbQfiU=
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=

View File

@@ -40,14 +40,23 @@ type Ldap struct {
BaseDNGroups string
}
// OpenIDConnect defined the avialable OpenID Connect configuration.
type OpenIDConnect struct {
Endpoint string
Realm string
SigningAlgs []string
Insecure bool
}
// Config combines all available configuration parts.
type Config struct {
File string
Log Log
Debug Debug
HTTP HTTP
Tracing Tracing
Ldap Ldap
File string
Log Log
Debug Debug
HTTP HTTP
Tracing Tracing
Ldap Ldap
OpenIDConnect OpenIDConnect
}
// New initializes a new configuration with or without defaults.

View File

@@ -169,5 +169,25 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
EnvVar: "GRAPH_LDAP_BASEDN_GROUPS",
Destination: &cfg.Ldap.BaseDNGroups,
},
&cli.StringFlag{
Name: "oidc-endpoint",
Value: "",
Usage: "OpenIDConnect endpoint",
EnvVar: "GRAPH_OIDC_ENDPOINT",
Destination: &cfg.OpenIDConnect.Endpoint,
},
&cli.BoolFlag{
Name: "oidc-insecure",
Usage: "OpenIDConnect endpoint",
EnvVar: "GRAPH_OIDC_INSECURE",
Destination: &cfg.OpenIDConnect.Insecure,
},
&cli.StringFlag{
Name: "oidc-realm",
Value: "",
Usage: "OpenIDConnect realm",
EnvVar: "GRAPH_OIDC_REALM",
Destination: &cfg.OpenIDConnect.Realm,
},
}
}

View File

@@ -4,6 +4,7 @@ import (
svc "github.com/owncloud/ocis-graph/pkg/service/v0"
"github.com/owncloud/ocis-graph/pkg/version"
"github.com/owncloud/ocis-pkg/middleware"
"github.com/owncloud/ocis-pkg/oidc"
"github.com/owncloud/ocis-pkg/service/http"
)
@@ -37,6 +38,12 @@ func Server(opts ...Option) (http.Service, error) {
middleware.Logger(
options.Logger,
),
middleware.OpenIDConnect(
oidc.Endpoint(options.Config.OpenIDConnect.Endpoint),
oidc.Realm(options.Config.OpenIDConnect.Realm),
oidc.Insecure(options.Config.OpenIDConnect.Insecure),
oidc.Logger(options.Logger),
),
),
)

View File

@@ -2,7 +2,6 @@ package svc
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -13,6 +12,7 @@ import (
"github.com/go-chi/render"
"github.com/owncloud/ocis-graph/pkg/config"
"github.com/owncloud/ocis-pkg/log"
"github.com/owncloud/ocis-pkg/oidc"
msgraph "github.com/yaegashi/msgraph.go/v1.0"
ldap "gopkg.in/ldap.v3"
)
@@ -42,7 +42,8 @@ func (g Graph) UserCtx(next http.Handler) http.Handler {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest)
return
}
user, err = g.ldapGetSingleEntry(userID, g.config.Ldap.BaseDNUsers)
filter := fmt.Sprintf("(entryuuid=%s)", userID)
user, err = g.ldapGetSingleEntry(g.config.Ldap.BaseDNUsers, filter)
if err != nil {
g.logger.Info().Err(err).Msgf("Failed to read user %s", userID)
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound)
@@ -64,7 +65,8 @@ func (g Graph) GroupCtx(next http.Handler) http.Handler {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest)
return
}
group, err := g.ldapGetSingleEntry(groupID, g.config.Ldap.BaseDNGroups)
filter := fmt.Sprintf("(entryuuid=%s)", groupID)
group, err := g.ldapGetSingleEntry(g.config.Ldap.BaseDNGroups, filter)
if err != nil {
g.logger.Info().Err(err).Msgf("Failed to read group %s", groupID)
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound)
@@ -78,21 +80,21 @@ func (g Graph) GroupCtx(next http.Handler) http.Handler {
// GetMe implements the Service interface.
func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) {
me := createUserModel(
"Alice",
"1234-5678-9000-000",
)
resp, err := json.Marshal(me)
claims := oidc.FromContext(r.Context())
g.logger.Info().Interface("Claims", claims).Msg("Claims in /me")
filter := fmt.Sprintf("(uid=%s)", claims.PreferredUsername)
user, err := g.ldapGetSingleEntry(g.config.Ldap.BaseDNUsers, filter)
if err != nil {
g.logger.Error().Err(err).Msgf("Failed to marshal object %s", me)
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError)
g.logger.Info().Err(err).Msgf("Failed to read user %s", claims.PreferredUsername)
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound)
return
}
me := createUserModelFromLDAP(user)
render.Status(r, http.StatusOK)
render.JSON(w, r, resp)
render.JSON(w, r, me)
}
// GetUsers implements the Service interface.
@@ -175,12 +177,11 @@ func (g Graph) GetGroup(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, createGroupModelFromLDAP(group))
}
func (g Graph) ldapGetSingleEntry(resourceID string, baseDn string) (*ldap.Entry, error) {
func (g Graph) ldapGetSingleEntry(baseDn string, filter string) (*ldap.Entry, error) {
conn, err := g.initLdap()
if err != nil {
return nil, err
}
filter := fmt.Sprintf("(entryuuid=%s)", resourceID)
result, err := g.ldapSearch(conn, filter, baseDn)
if err != nil {
return nil, err
@@ -229,18 +230,6 @@ func (g Graph) ldapSearch(con *ldap.Conn, filter string, baseDN string) (*ldap.S
return con.Search(search)
}
func createUserModel(displayName string, id string) *msgraph.User {
return &msgraph.User{
DisplayName: &displayName,
GivenName: &displayName,
DirectoryObject: msgraph.DirectoryObject{
Entity: msgraph.Entity{
ID: &id,
},
},
}
}
func createUserModelFromLDAP(entry *ldap.Entry) *msgraph.User {
displayName := entry.GetAttributeValue("displayname")
givenName := entry.GetAttributeValue("givenname")

View File

@@ -29,6 +29,7 @@ func NewService(opts ...Option) Service {
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
r.Route("/v1.0", func(r chi.Router) {
r.Get("/me", svc.GetMe)
r.Route("/users", func(r chi.Router) {
r.Get("/", svc.GetUsers)
r.Route("/{userID}", func(r chi.Router) {

View File

@@ -1,2 +1,2 @@
# backend
-r '^(cmd|pkg)/.*\.go$' -R '^node_modules/' -s -- sh -c 'make bin/ocis-graph-debug && bin/ocis-graph-debug --log-level debug server --debug-pprof --debug-zpages'
-r '^(cmd|pkg)/.*\.go$' -R '^node_modules/' -s -- sh -c 'make bin/ocis-graph-debug && bin/ocis-graph-debug --log-level debug server --debug-pprof --debug-zpages --oidc-endpoint="https://deepdiver" --oidc-insecure=1'