Merge branch 'next' into next-main

This commit is contained in:
Tim Möhlmann 2023-10-12 15:08:55 +03:00
commit d9487ef77d
118 changed files with 6091 additions and 981 deletions

View file

@ -1,21 +1,34 @@
package exampleop
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"github.com/gorilla/mux"
"github.com/go-chi/chi"
"github.com/gorilla/securecookie"
"github.com/sirupsen/logrus"
"github.com/zitadel/oidc/v2/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op"
)
type deviceAuthenticate interface {
CheckUsernamePasswordSimple(username, password string) error
op.DeviceAuthorizationStorage
// GetDeviceAuthorizationByUserCode resturns the current state of the device authorization flow,
// identified by the user code.
GetDeviceAuthorizationByUserCode(ctx context.Context, userCode string) (*op.DeviceAuthorizationState, error)
// CompleteDeviceAuthorization marks a device authorization entry as Completed,
// identified by userCode. The Subject is added to the state, so that
// GetDeviceAuthorizatonState can use it to create a new Access Token.
CompleteDeviceAuthorization(ctx context.Context, userCode, subject string) error
// DenyDeviceAuthorization marks a device authorization entry as Denied.
DenyDeviceAuthorization(ctx context.Context, userCode string) error
}
type deviceLogin struct {
@ -23,14 +36,14 @@ type deviceLogin struct {
cookie *securecookie.SecureCookie
}
func registerDeviceAuth(storage deviceAuthenticate, router *mux.Router) {
func registerDeviceAuth(storage deviceAuthenticate, router chi.Router) {
l := &deviceLogin{
storage: storage,
cookie: securecookie.New(securecookie.GenerateRandomKey(32), nil),
}
router.HandleFunc("", l.userCodeHandler)
router.Path("/login").Methods(http.MethodPost).HandlerFunc(l.loginHandler)
router.HandleFunc("/", l.userCodeHandler)
router.Post("/login", l.loginHandler)
router.HandleFunc("/confirm", l.confirmHandler)
}

View file

@ -5,13 +5,13 @@ import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/zitadel/oidc/v2/pkg/op"
"github.com/go-chi/chi"
"github.com/zitadel/oidc/v3/pkg/op"
)
type login struct {
authenticate authenticate
router *mux.Router
router chi.Router
callback func(context.Context, string) string
}
@ -25,9 +25,9 @@ func NewLogin(authenticate authenticate, callback func(context.Context, string)
}
func (l *login) createRouter(issuerInterceptor *op.IssuerInterceptor) {
l.router = mux.NewRouter()
l.router.Path("/username").Methods("GET").HandlerFunc(l.loginHandler)
l.router.Path("/username").Methods("POST").HandlerFunc(issuerInterceptor.HandlerFunc(l.checkLoginHandler))
l.router = chi.NewRouter()
l.router.Get("/username", l.loginHandler)
l.router.Post("/username", issuerInterceptor.HandlerFunc(l.checkLoginHandler))
}
type authenticate interface {

View file

@ -4,13 +4,16 @@ import (
"crypto/sha256"
"log"
"net/http"
"sync/atomic"
"time"
"github.com/gorilla/mux"
"github.com/go-chi/chi"
"github.com/zitadel/logging"
"golang.org/x/exp/slog"
"golang.org/x/text/language"
"github.com/zitadel/oidc/v2/example/server/storage"
"github.com/zitadel/oidc/v2/pkg/op"
"github.com/zitadel/oidc/v3/example/server/storage"
"github.com/zitadel/oidc/v3/pkg/op"
)
const (
@ -31,26 +34,33 @@ type Storage interface {
deviceAuthenticate
}
// simple counter for request IDs
var counter atomic.Int64
// SetupServer creates an OIDC server with Issuer=http://localhost:<port>
//
// Use one of the pre-made clients in storage/clients.go or register a new one.
func SetupServer(issuer string, storage Storage, extraOptions ...op.Option) *mux.Router {
func SetupServer(issuer string, storage Storage, logger *slog.Logger, wrapServer bool, extraOptions ...op.Option) chi.Router {
// the OpenID Provider requires a 32-byte key for (token) encryption
// be sure to create a proper crypto random key and manage it securely!
key := sha256.Sum256([]byte("test"))
router := mux.NewRouter()
router := chi.NewRouter()
router.Use(logging.Middleware(
logging.WithLogger(logger),
logging.WithIDFunc(func() slog.Attr {
return slog.Int64("id", counter.Add(1))
}),
))
// for simplicity, we provide a very small default page for users who have signed out
router.HandleFunc(pathLoggedOut, func(w http.ResponseWriter, req *http.Request) {
_, err := w.Write([]byte("signed out successfully"))
if err != nil {
log.Printf("error serving logged out page: %v", err)
}
w.Write([]byte("signed out successfully"))
// no need to check/log error, this will be handeled by the middleware.
})
// creation of the OpenIDProvider with the just created in-memory Storage
provider, err := newOP(storage, issuer, key, extraOptions...)
provider, err := newOP(storage, issuer, key, logger, extraOptions...)
if err != nil {
log.Fatal(err)
}
@ -62,17 +72,23 @@ func SetupServer(issuer string, storage Storage, extraOptions ...op.Option) *mux
// regardless of how many pages / steps there are in the process, the UI must be registered in the router,
// so we will direct all calls to /login to the login UI
router.PathPrefix("/login/").Handler(http.StripPrefix("/login", l.router))
router.Mount("/login/", http.StripPrefix("/login", l.router))
router.PathPrefix("/device").Subrouter()
registerDeviceAuth(storage, router.PathPrefix("/device").Subrouter())
router.Route("/device", func(r chi.Router) {
registerDeviceAuth(storage, r)
})
handler := http.Handler(provider)
if wrapServer {
handler = op.NewLegacyServer(provider, *op.DefaultEndpoints)
}
// we register the http handler of the OP on the root, so that the discovery endpoint (/.well-known/openid-configuration)
// is served on the correct path
//
// if your issuer ends with a path (e.g. http://localhost:9998/custom/path/),
// then you would have to set the path prefix (/custom/path/)
router.PathPrefix("/").Handler(provider.HttpHandler())
router.Mount("/", handler)
return router
}
@ -80,7 +96,7 @@ func SetupServer(issuer string, storage Storage, extraOptions ...op.Option) *mux
// newOP will create an OpenID Provider for localhost on a specified port with a given encryption key
// and a predefined default logout uri
// it will enable all options (see descriptions)
func newOP(storage op.Storage, issuer string, key [32]byte, extraOptions ...op.Option) (op.OpenIDProvider, error) {
func newOP(storage op.Storage, issuer string, key [32]byte, logger *slog.Logger, extraOptions ...op.Option) (op.OpenIDProvider, error) {
config := &op.Config{
CryptoKey: key,
@ -114,10 +130,12 @@ func newOP(storage op.Storage, issuer string, key [32]byte, extraOptions ...op.O
}
handler, err := op.NewOpenIDProvider(issuer, config, storage,
append([]op.Option{
// we must explicitly allow the use of the http issuer
//we must explicitly allow the use of the http issuer
op.WithAllowInsecure(),
// as an example on how to customize an endpoint this will change the authorization_endpoint from /authorize to /auth
op.WithCustomAuthEndpoint(op.NewEndpoint("auth")),
// Pass our logger to the OP
op.WithLogger(logger.WithGroup("op")),
}, extraOptions...)...,
)
if err != nil {