Skip to content

Commit

Permalink
Merge pull request #456 from zitadel/next-main
Browse files Browse the repository at this point in the history
Merge next into main in order to release v3. Merge conflicts were handled in an intermediate branch.

BREAKING CHANGE - Just making sure v3 release is triggered.
  • Loading branch information
muhlemmer authored Oct 13, 2023
2 parents bb115d8 + d9487ef commit 976b406
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 976b406

Please sign in to comment.