Skip to content

Commit

Permalink
Merge branch 'next' into next-main
Browse files Browse the repository at this point in the history
  • Loading branch information
muhlemmer committed Oct 12, 2023
2 parents bb115d8 + 0f8a058 commit d9487ef
Show file tree
Hide file tree
Showing 118 changed files with 6,089 additions and 979 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ Check the `/example` folder where example code for different scenarios is locate
```bash
# start oidc op server
# oidc discovery http://localhost:9998/.well-known/openid-configuration
go run github.com/zitadel/oidc/v2/example/server
go run github.com/zitadel/oidc/v3/example/server
# start oidc web client (in a new terminal)
CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://localhost:9998/ SCOPES="openid profile" PORT=9999 go run github.com/zitadel/oidc/v2/example/client/app
CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://localhost:9998/ SCOPES="openid profile" PORT=9999 go run github.com/zitadel/oidc/v3/example/client/app
```

- open http://localhost:9999/login in your browser
Expand All @@ -56,11 +56,11 @@ CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://localhost:9998/ SCOPES="openid

for the dynamic issuer, just start it with:
```bash
go run github.com/zitadel/oidc/v2/example/server/dynamic
go run github.com/zitadel/oidc/v3/example/server/dynamic
```
the oidc web client above will still work, but if you add `oidc.local` (pointing to 127.0.0.1) in your hosts file you can also start it with:
```bash
CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://oidc.local:9998/ SCOPES="openid profile" PORT=9999 go run github.com/zitadel/oidc/v2/example/client/app
CLIENT_ID=web CLIENT_SECRET=secret ISSUER=http://oidc.local:9998/ SCOPES="openid profile" PORT=9999 go run github.com/zitadel/oidc/v3/example/client/app
```

> Note: Usernames are suffixed with the hostname (`test-user@localhost` or `[email protected]`)
Expand Down
21 changes: 11 additions & 10 deletions example/client/api/api.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"encoding/json"
"fmt"
"log"
Expand All @@ -9,11 +10,11 @@ import (
"strings"
"time"

"github.com/gorilla/mux"
"github.com/go-chi/chi"
"github.com/sirupsen/logrus"

"github.com/zitadel/oidc/v2/pkg/client/rs"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/client/rs"
"github.com/zitadel/oidc/v3/pkg/oidc"
)

const (
Expand All @@ -27,12 +28,12 @@ func main() {
port := os.Getenv("PORT")
issuer := os.Getenv("ISSUER")

provider, err := rs.NewResourceServerFromKeyFile(issuer, keyPath)
provider, err := rs.NewResourceServerFromKeyFile(context.TODO(), issuer, keyPath)
if err != nil {
logrus.Fatalf("error creating provider %s", err.Error())
}

router := mux.NewRouter()
router := chi.NewRouter()

// public url accessible without any authorization
// will print `OK` and current timestamp
Expand All @@ -47,7 +48,7 @@ func main() {
if !ok {
return
}
resp, err := rs.Introspect(r.Context(), provider, token)
resp, err := rs.Introspect[*oidc.IntrospectionResponse](r.Context(), provider, token)
if err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
Expand All @@ -68,14 +69,14 @@ func main() {
if !ok {
return
}
resp, err := rs.Introspect(r.Context(), provider, token)
resp, err := rs.Introspect[*oidc.IntrospectionResponse](r.Context(), provider, token)
if err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
params := mux.Vars(r)
requestedClaim := params["claim"]
requestedValue := params["value"]
requestedClaim := chi.URLParam(r, "claim")
requestedValue := chi.URLParam(r, "value")

value, ok := resp.Claims[requestedClaim].(string)
if !ok || value == "" || value != requestedValue {
http.Error(w, "claim does not match", http.StatusForbidden)
Expand Down
51 changes: 44 additions & 7 deletions example/client/app/app.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package main

import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"sync/atomic"
"time"

"github.com/google/uuid"
"github.com/sirupsen/logrus"
"golang.org/x/exp/slog"

"github.com/zitadel/oidc/v2/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v2/pkg/http"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
)

var (
Expand All @@ -32,9 +36,25 @@ func main() {
redirectURI := fmt.Sprintf("http://localhost:%v%v", port, callbackPath)
cookieHandler := httphelper.NewCookieHandler(key, key, httphelper.WithUnsecure())

logger := slog.New(
slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
AddSource: true,
Level: slog.LevelDebug,
}),
)
client := &http.Client{
Timeout: time.Minute,
}
// enable outgoing request logging
logging.EnableHTTPClient(client,
logging.WithClientGroup("client"),
)

options := []rp.Option{
rp.WithCookieHandler(cookieHandler),
rp.WithVerifierOpts(rp.WithIssuedAtOffset(5 * time.Second)),
rp.WithHTTPClient(client),
rp.WithLogger(logger),
}
if clientSecret == "" {
options = append(options, rp.WithPKCE(cookieHandler))
Expand All @@ -43,7 +63,10 @@ func main() {
options = append(options, rp.WithJWTProfile(rp.SignerFromKeyPath(keyPath)))
}

provider, err := rp.NewRelyingPartyOIDC(issuer, clientID, clientSecret, redirectURI, scopes, options...)
// One can add a logger to the context,
// pre-defining log attributes as required.
ctx := logging.ToContext(context.TODO(), logger)
provider, err := rp.NewRelyingPartyOIDC(ctx, issuer, clientID, clientSecret, redirectURI, scopes, options...)
if err != nil {
logrus.Fatalf("error creating provider %s", err.Error())
}
Expand Down Expand Up @@ -118,8 +141,22 @@ func main() {
//
// http.Handle(callbackPath, rp.CodeExchangeHandler(marshalToken, provider))

// simple counter for request IDs
var counter atomic.Int64
// enable incomming request logging
mw := logging.Middleware(
logging.WithLogger(logger),
logging.WithGroup("server"),
logging.WithIDFunc(func() slog.Attr {
return slog.Int64("id", counter.Add(1))
}),
)

lis := fmt.Sprintf("127.0.0.1:%s", port)
logrus.Infof("listening on http://%s/", lis)
logrus.Info("press ctrl+c to stop")
logrus.Fatal(http.ListenAndServe(lis, nil))
logger.Info("server listening, press ctrl+c to stop", "addr", lis)
err = http.ListenAndServe(lis, mw(http.DefaultServeMux))
if err != http.ErrServerClosed {
logger.Error("server terminated", "error", err)
os.Exit(1)
}
}
8 changes: 4 additions & 4 deletions example/client/device/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (

"github.com/sirupsen/logrus"

"github.com/zitadel/oidc/v2/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v2/pkg/http"
"github.com/zitadel/oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
)

var (
Expand All @@ -39,13 +39,13 @@ func main() {
options = append(options, rp.WithJWTProfile(rp.SignerFromKeyPath(keyPath)))
}

provider, err := rp.NewRelyingPartyOIDC(issuer, clientID, clientSecret, "", scopes, options...)
provider, err := rp.NewRelyingPartyOIDC(ctx, issuer, clientID, clientSecret, "", scopes, options...)
if err != nil {
logrus.Fatalf("error creating provider %s", err.Error())
}

logrus.Info("starting device authorization flow")
resp, err := rp.DeviceAuthorization(scopes, provider)
resp, err := rp.DeviceAuthorization(ctx, scopes, provider, nil)
if err != nil {
logrus.Fatal(err)
}
Expand Down
8 changes: 4 additions & 4 deletions example/client/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"golang.org/x/oauth2"
githubOAuth "golang.org/x/oauth2/github"

"github.com/zitadel/oidc/v2/pkg/client/rp"
"github.com/zitadel/oidc/v2/pkg/client/rp/cli"
"github.com/zitadel/oidc/v2/pkg/http"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/client/rp"
"github.com/zitadel/oidc/v3/pkg/client/rp/cli"
"github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
)

var (
Expand Down
6 changes: 3 additions & 3 deletions example/client/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"

"github.com/zitadel/oidc/v2/pkg/client/profile"
"github.com/zitadel/oidc/v3/pkg/client/profile"
)

var client = http.DefaultClient
Expand All @@ -25,7 +25,7 @@ func main() {
scopes := strings.Split(os.Getenv("SCOPES"), " ")

if keyPath != "" {
ts, err := profile.NewJWTProfileTokenSourceFromKeyFile(issuer, keyPath, scopes)
ts, err := profile.NewJWTProfileTokenSourceFromKeyFile(context.TODO(), issuer, keyPath, scopes)
if err != nil {
logrus.Fatalf("error creating token source %s", err.Error())
}
Expand Down Expand Up @@ -76,7 +76,7 @@ func main() {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
ts, err := profile.NewJWTProfileTokenSourceFromKeyFileData(issuer, key, scopes)
ts, err := profile.NewJWTProfileTokenSourceFromKeyFileData(context.TODO(), issuer, key, scopes)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
Expand Down
12 changes: 6 additions & 6 deletions example/server/dynamic/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"html/template"
"net/http"

"github.com/gorilla/mux"
"github.com/go-chi/chi"

"github.com/zitadel/oidc/v2/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op"
)

const (
Expand Down Expand Up @@ -43,7 +43,7 @@ var (

type login struct {
authenticate authenticate
router *mux.Router
router chi.Router
callback func(context.Context, string) string
}

Expand All @@ -57,9 +57,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.With(issuerInterceptor.Handler).Post("/username", l.checkLoginHandler)
}

type authenticate interface {
Expand Down
12 changes: 6 additions & 6 deletions example/server/dynamic/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (
"log"
"net/http"

"github.com/gorilla/mux"
"github.com/go-chi/chi"
"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 (
Expand Down Expand Up @@ -47,7 +47,7 @@ func main() {
//be sure to create a proper crypto random key and manage it securely!
key := sha256.Sum256([]byte("test"))

router := mux.NewRouter()
router := chi.NewRouter()

//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) {
Expand Down Expand Up @@ -76,15 +76,15 @@ func main() {

//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))

//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("/custom/path/").Handler(http.StripPrefix("/custom/path", provider.HttpHandler()))
router.PathPrefix("/").Handler(provider.HttpHandler())
router.Mount("/", provider)

server := &http.Server{
Addr: ":" + port,
Expand Down
23 changes: 18 additions & 5 deletions example/server/exampleop/device.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
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 {
storage deviceAuthenticate
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)
}

Expand Down
Loading

0 comments on commit d9487ef

Please sign in to comment.