feat(11.1-04): add the Database section and the core Services pages
- docs/database: models, migrations, queries and pagination, relations, casts and validation, attachments and transactions (lagoon.Transaction, lagoon.AfterCommit, nested savepoints, lagoon.OnDatabase) - docs/services: configuration, events, routing with auth groups, rate limiting, authentication, the OAuth server, mail and localization - runnable Examples for lagoon, attach, compass, surf, wire, bouncer, wristband, postcard, phrasebook and festival; lagoon TestDocs* regions run on the package's Postgres harness through DocsDB - 15 new required pages
This commit is contained in:
105
modules/bouncer/example_test.go
Normal file
105
modules/bouncer/example_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package bouncer_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/bouncer"
|
||||
)
|
||||
|
||||
// testSecret is a test-only signing secret. A real application reads its
|
||||
// secret from configuration and never commits it.
|
||||
const testSecret = "test-only-secret-with-at-least-32-bytes"
|
||||
|
||||
func ExampleMint() {
|
||||
const issuer = "http://127.0.0.1:8080/api/login"
|
||||
token, _, err := bouncer.Mint(testSecret, "42", issuer, time.Hour)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
sub, iat, exp, _, err := bouncer.VerifyClaims(token, testSecret)
|
||||
fmt.Println(sub, exp.Sub(iat), err)
|
||||
|
||||
// A frontend token never passes a backend check, and a wrong secret fails.
|
||||
_, _, _, _, err = bouncer.VerifyClaimsAudience(token, testSecret, bouncer.AudienceBackend)
|
||||
fmt.Println(err != nil)
|
||||
_, err = bouncer.Verify(token, "another-secret-with-at-least-32-bytes")
|
||||
fmt.Println(err != nil)
|
||||
|
||||
// Refresh reissues the token and blacklists the old jti after the grace.
|
||||
bl := bouncer.NewMemoryBlacklist()
|
||||
fresh, err := bouncer.Refresh(testSecret, token, 14*24*time.Hour, bl, 0, issuer)
|
||||
fmt.Println(fresh != token, err)
|
||||
_, _, _, jti, _ := bouncer.VerifyClaims(token, testSecret)
|
||||
revoked, _ := bl.IsBlacklisted(context.Background(), jti)
|
||||
fmt.Println(revoked)
|
||||
// Output:
|
||||
// 42 1h0m0s <nil>
|
||||
// true
|
||||
// true
|
||||
// true <nil>
|
||||
// true
|
||||
}
|
||||
|
||||
// users loads the principal behind a token subject.
|
||||
type users struct{}
|
||||
|
||||
func (users) FindByID(ctx context.Context, id uint) (*bouncer.Principal, error) {
|
||||
return &bouncer.Principal{ID: id, PreferredLocale: "pl"}, nil
|
||||
}
|
||||
|
||||
func ExampleNewJWTGuard() {
|
||||
guards := bouncer.NewRegistry()
|
||||
guard := bouncer.NewJWTGuard(testSecret, users{}, bouncer.NewMemoryBlacklist(), "token")
|
||||
if err := guards.Register("acme.blog", "acme.auth", guard); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
auth, err := guards.Middleware("acme.auth")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
me := auth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := bouncer.User(r.Context())
|
||||
fmt.Fprintf(w, "user %d, locale %s", user.ID, user.PreferredLocale)
|
||||
}))
|
||||
|
||||
token, _, _ := bouncer.Mint(testSecret, "42", "http://127.0.0.1:8080/api/login", time.Hour)
|
||||
for _, set := range []func(*http.Request){
|
||||
func(r *http.Request) {},
|
||||
func(r *http.Request) { r.Header.Set("Authorization", "Bearer "+token) },
|
||||
func(r *http.Request) { r.AddCookie(&http.Cookie{Name: "token", Value: token}) },
|
||||
} {
|
||||
req := httptest.NewRequest("GET", "/api/me", nil)
|
||||
set(req)
|
||||
rec := httptest.NewRecorder()
|
||||
me.ServeHTTP(rec, req)
|
||||
fmt.Println(rec.Code, strings.TrimSpace(rec.Body.String()))
|
||||
}
|
||||
// Output:
|
||||
// 401 {"error":true,"message":"Token not provided"}
|
||||
// 200 user 42, locale pl
|
||||
// 200 user 42, locale pl
|
||||
}
|
||||
|
||||
func ExampleHashPassword() {
|
||||
hash, err := bouncer.HashPassword(10, "correct horse battery staple")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(bouncer.CheckPassword(hash, "correct horse battery staple"))
|
||||
fmt.Println(bouncer.CheckPassword(hash, "wrong"))
|
||||
// After raising the configured cost, rehash on the next successful login.
|
||||
fmt.Println(bouncer.NeedsRehash(hash, 12))
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
}
|
||||
Reference in New Issue
Block a user