Commit b27894f
Changed files (11)
bin/api
@@ -55,6 +55,10 @@ class Entity
def to_h
@attributes
end
+
+ def to_gid
+ ::GlobalID.create(self, app: "example")
+ end
end
class Organization < Entity
@@ -73,11 +77,11 @@ module HTTPHelpers
authorization = Rack::Auth::AbstractRequest.new(request.env)
return false unless authorization.provided?
- response = rpc.allowed(
+ response = rpc.allowed({
subject: authorization.params,
permission: permission,
- resource: ::GlobalID.create(resource, app: "example").to_s
- )
+ resource: resource.to_gid.to_s,
+ }, headers: { 'Authorization' => "Bearer #{authorization.params}"})
response.error.nil? && response.data.result
end
@@ -93,11 +97,11 @@ module HTTPHelpers
http_response(code: 201, body: JSON.pretty_generate(body.to_h))
end
- def json_unauthorized(permission)
+ def json_unauthorized(permission, resource)
http_response(code: 401, body: JSON.pretty_generate({
error: {
code: 401,
- message: "`#{permission}` is required",
+ message: "`#{permission}` is required on `#{resource.to_gid}`",
}
}))
end
@@ -128,15 +132,21 @@ class API
when "/organizations", "/organizations.json"
return json_ok(Organization.all.map(&:to_h))
when "/projects", "/projects.json"
- return json_ok(Project.all.map(&:to_h))
+ resource = Organization.default
+ if authorized?(request, :read_project, resource)
+ return json_ok(Project.all.map(&:to_h))
+ else
+ return json_unauthorized(:read_project, resource)
+ end
end
when Rack::POST
case request.path
when "/projects", "/projects.json"
- if authorized?(request, :create_project, Organization.default)
+ resource = Organization.default
+ if authorized?(request, :create_project, resource)
return json_created(Project.create!(JSON.parse(request.body.read, symbolize_names: true)))
else
- return json_unauthorized(:create_project)
+ return json_unauthorized(:create_project, resource)
end
end
end
bin/idp
@@ -322,6 +322,7 @@ module Authz
class OrganizationPolicy < DeclarativePolicy::Base
condition(:owner) { true }
+ rule { owner }.enable :read_project
rule { owner }.enable :create_project
end
@@ -334,9 +335,9 @@ module Authz
def to_jwt
[
- Base64.strict_encode64(JSON.generate({alg: "RS256", typ: "JWT"})),
+ Base64.strict_encode64(JSON.generate(alg: "none")),
Base64.strict_encode64(JSON.generate(claims)),
- Base64.strict_encode64(JSON.generate({})),
+ ""
].join(".")
end
end
@@ -354,8 +355,13 @@ module Authz
def can?(request)
subject = subject_of(request.subject)
resource = resource_from(request.resource)
+ permission = request.permission.to_sym
+
policy = DeclarativePolicy.policy_for(subject, resource)
- policy.can?(request.permission.to_sym)
+ policy.can?(permission)
+ rescue StandardError => error
+ puts error.inspect
+ false
end
def subject_of(token)
@@ -371,7 +377,7 @@ module Authz
def from_jwt(token)
token
.split('.', 3)
- .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) }
+ .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) rescue {} }
end
end
end
bin/ui
@@ -108,13 +108,7 @@ class UI
}
)
end
- if response.code.to_i == 200
- [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate(
- request.params.merge(JSON.parse(response.body))
- )]]
- else
- [response.code, response.header, [response.body]]
- end
+ [response.code, response.header, [response.body]]
end
def saml_post_to_idp(request)
cmd/gtwy/main.go
@@ -1,57 +1,12 @@
package main
import (
- "fmt"
"log"
- "net"
- "net/http"
- "github.com/casbin/casbin/v2"
"github.com/xlgmokha/x/pkg/env"
- "github.com/xlgmokha/x/pkg/x"
- "gitlab.com/mokhax/spike/pkg/authz"
- "gitlab.com/mokhax/spike/pkg/cfg"
- "gitlab.com/mokhax/spike/pkg/prxy"
- "gitlab.com/mokhax/spike/pkg/srv"
+ "gitlab.com/mokhax/spike/pkg/app"
)
-func WithCasbin() authz.Authorizer {
- enforcer := x.Must(casbin.NewEnforcer("model.conf", "policy.csv"))
-
- return authz.AuthorizerFunc(func(r *http.Request) bool {
- host, _, err := net.SplitHostPort(r.Host)
- if err != nil {
- return false
- }
-
- subject := "71cbc18e-bd41-4229-9ad2-749546a2a4a7" // TODO:: unpack sub claim in JWT
- ok, err := enforcer.Enforce(subject, host, r.Method, r.URL.Path)
- if err != nil {
- fmt.Printf("%v\n", err)
- return false
- }
-
- fmt.Printf("%v: %v %v%v\n", ok, r.Method, host, r.URL.Path)
- return ok
- })
-}
-
-func WithRoutes() cfg.Option {
- return func(c *cfg.Config) {
- mux := http.NewServeMux()
- mux.Handle("/", authz.HTTP(WithCasbin(), prxy.New(map[string]string{
- "idp.example.com": "http://localhost:8282",
- "ui.example.com": "http://localhost:8283",
- "api.example.com": "http://localhost:8284",
- })))
-
- cfg.WithMux(mux)(c)
- }
-}
-
func main() {
- log.Fatal(srv.Run(cfg.New(
- env.Fetch("BIND_ADDR", ":8080"),
- WithRoutes(),
- )))
+ log.Fatal(app.Start(env.Fetch("BIND_ADDR", ":8080")))
}
pkg/app/app.go
@@ -0,0 +1,44 @@
+package app
+
+import (
+ "fmt"
+ "net"
+ "net/http"
+
+ "github.com/casbin/casbin/v3"
+ "github.com/xlgmokha/x/pkg/x"
+ "gitlab.com/mokhax/spike/pkg/authz"
+ "gitlab.com/mokhax/spike/pkg/cfg"
+ "gitlab.com/mokhax/spike/pkg/srv"
+)
+
+func WithCasbin() authz.Authorizer {
+ enforcer := x.Must(casbin.NewEnforcer("model.conf", "policy.csv"))
+
+ return authz.AuthorizerFunc(func(r *http.Request) bool {
+ host, _, err := net.SplitHostPort(r.Host)
+ if err != nil {
+ return false
+ }
+
+ subject, found := authz.TokenFrom(r).Subject()
+ if !found {
+ subject = "*"
+ }
+ ok, err := enforcer.Enforce(subject, host, r.Method, r.URL.Path)
+ if err != nil {
+ fmt.Printf("%v\n", err)
+ return false
+ }
+
+ fmt.Printf("%v: %v -> %v %v%v\n", ok, subject, r.Method, host, r.URL.Path)
+ return ok
+ })
+}
+
+func Start(bindAddr string) error {
+ return srv.Run(cfg.New(
+ bindAddr,
+ cfg.WithMux(authz.HTTP(WithCasbin(), Routes())),
+ ))
+}
pkg/app/routes.go
@@ -0,0 +1,17 @@
+package app
+
+import (
+ "net/http"
+
+ "gitlab.com/mokhax/spike/pkg/prxy"
+)
+
+func Routes() http.Handler {
+ mux := http.NewServeMux()
+ mux.Handle("/", prxy.New(map[string]string{
+ "idp.example.com": "http://localhost:8282",
+ "ui.example.com": "http://localhost:8283",
+ "api.example.com": "http://localhost:8284",
+ }))
+ return mux
+}
pkg/authz/token.go
@@ -0,0 +1,30 @@
+package authz
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/lestrrat-go/jwx/v3/jwt"
+)
+
+func TokenFrom(r *http.Request) jwt.Token {
+ authorization := r.Header.Get("Authorization")
+ if authorization == "" || !strings.Contains(authorization, "Bearer") {
+ return jwt.New()
+ }
+
+ token, err := jwt.ParseRequest(r,
+ jwt.WithContext(r.Context()),
+ jwt.WithHeaderKey("Authorization"),
+ jwt.WithValidate(false), // TODO:: Connect this to a JSON Web Key Set
+ jwt.WithVerify(false), // TODO:: Connect this to a JSON Web Key Set
+ )
+
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ return jwt.New()
+ }
+
+ return token
+}
test/e2e_test.go
@@ -11,6 +11,7 @@ import (
"github.com/playwright-community/playwright-go"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/xlgmokha/x/pkg/env"
"github.com/xlgmokha/x/pkg/serde"
"github.com/xlgmokha/x/pkg/x"
@@ -76,20 +77,34 @@ func TestAuthx(t *testing.T) {
assert.Contains(t, page.URL(), "http://ui.example.com:8080/oauth/callback")
content := x.Must(page.Locator("pre").First().InnerText())
item := x.Must(serde.FromJSON[oauth2.Token](strings.NewReader(content)))
- assert.NotEmpty(t, item.AccessToken)
- assert.Equal(t, "Bearer", item.TokenType)
- assert.NotEmpty(t, item.RefreshToken)
+ require.NotEmpty(t, item.AccessToken)
+ require.Equal(t, "Bearer", item.TokenType)
+ require.NotEmpty(t, item.RefreshToken)
- t.Run("lists all the organizations", func(t *testing.T) {
+ t.Run("GET http://api.example.com:8080/organizations.json", func(t *testing.T) {
response := x.Must(http.Get("http://api.example.com:8080/organizations.json"))
- assert.Equal(t, http.StatusOK, response.StatusCode)
+ assert.Equal(t, http.StatusForbidden, response.StatusCode)
+ })
+
+ t.Run("GET http://api.example.com:8080/organizations.json with Authorization", func(t *testing.T) {
+ request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/organizations.json", nil))
+ request.Header.Add("Authorization", "Bearer "+item.AccessToken)
+ response := x.Must(client.Do(request))
+ require.Equal(t, http.StatusOK, response.StatusCode)
organizations := x.Must(serde.FromJSON[[]map[string]string](response.Body))
assert.NotNil(t, organizations)
})
- t.Run("lists all the projects", func(t *testing.T) {
+ t.Run("GET http://api.example.com:8080/projects.json", func(t *testing.T) {
response := x.Must(http.Get("http://api.example.com:8080/projects.json"))
- assert.Equal(t, http.StatusOK, response.StatusCode)
+ assert.Equal(t, http.StatusForbidden, response.StatusCode)
+ })
+
+ t.Run("GET http://api.example.com:8080/projects.json with Authorization", func(t *testing.T) {
+ request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/projects.json", nil))
+ request.Header.Add("Authorization", "Bearer "+item.AccessToken)
+ response := x.Must(client.Do(request))
+ require.Equal(t, http.StatusOK, response.StatusCode)
projects := x.Must(serde.FromJSON[[]map[string]string](response.Body))
assert.NotNil(t, projects)
})
@@ -100,18 +115,18 @@ func TestAuthx(t *testing.T) {
request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://api.example.com:8080/projects", io))
request.Header.Add("Authorization", "Bearer "+item.AccessToken)
response := x.Must(client.Do(request))
- assert.Equal(t, http.StatusCreated, response.StatusCode)
+ require.Equal(t, http.StatusCreated, response.StatusCode)
project := x.Must(serde.FromJSON[map[string]string](response.Body))
assert.Equal(t, "example", project["name"])
})
- t.Run("creates another projects", func(t *testing.T) {
+ t.Run("creates another project", func(t *testing.T) {
io := bytes.NewBuffer(nil)
assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "example2"}))
request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://api.example.com:8080/projects.json", io))
request.Header.Add("Authorization", "Bearer "+item.AccessToken)
response := x.Must(client.Do(request))
- assert.Equal(t, http.StatusCreated, response.StatusCode)
+ require.Equal(t, http.StatusCreated, response.StatusCode)
project := x.Must(serde.FromJSON[map[string]string](response.Body))
assert.Equal(t, "example2", project["name"])
})
@@ -121,7 +136,7 @@ func TestAuthx(t *testing.T) {
t.Run("OAuth", func(t *testing.T) {
t.Run("GET /.well-known/oauth-authorization-server", func(t *testing.T) {
response := x.Must(client.Get("http://idp.example.com:8080/.well-known/oauth-authorization-server"))
- assert.Equal(t, http.StatusOK, response.StatusCode)
+ require.Equal(t, http.StatusOK, response.StatusCode)
metadata := x.Must(serde.FromJSON[map[string]interface{}](response.Body))
assert.Equal(t, "http://idp.example.com:8080/.well-known/oauth-authorization-server", metadata["issuer"])
assert.Equal(t, "http://idp.example.com:8080/oauth/authorize", metadata["authorization_endpoint"])
@@ -149,7 +164,7 @@ func TestAuthx(t *testing.T) {
t.Run("GET /.well-known/openid-configuration", func(t *testing.T) {
response := x.Must(client.Get("http://idp.example.com:8080/.well-known/openid-configuration"))
- assert.Equal(t, http.StatusOK, response.StatusCode)
+ require.Equal(t, http.StatusOK, response.StatusCode)
metadata := x.Must(serde.FromJSON[map[string]interface{}](response.Body))
assert.Equal(t, "http://idp.example.com:8080/.well-known/oauth-authorization-server", metadata["issuer"])
assert.Equal(t, "http://idp.example.com:8080/oauth/authorize", metadata["authorization_endpoint"])
@@ -230,14 +245,14 @@ func TestAuthx(t *testing.T) {
t.Run("token is usable against REST API", func(t *testing.T) {
client := conf.Client(ctx, credentials)
response := x.Must(client.Get("http://api.example.com:8080/projects.json"))
- assert.Equal(t, http.StatusOK, response.StatusCode)
+ require.Equal(t, http.StatusOK, response.StatusCode)
projects := x.Must(serde.FromJSON[[]map[string]string](response.Body))
assert.NotNil(t, projects)
io := bytes.NewBuffer(nil)
assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "foo"}))
response = x.Must(client.Post("http://api.example.com:8080/projects", "application/json", io))
- assert.Equal(t, http.StatusCreated, response.StatusCode)
+ require.Equal(t, http.StatusCreated, response.StatusCode)
project := x.Must(serde.FromJSON[map[string]string](response.Body))
assert.Equal(t, "foo", project["name"])
})
go.mod
@@ -3,27 +3,36 @@ module gitlab.com/mokhax/spike
go 1.24.0
require (
- github.com/casbin/casbin/v2 v2.103.0
+ github.com/casbin/casbin/v3 v3.0.0-beta.7
+ github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3
github.com/magefile/mage v1.15.0
github.com/playwright-community/playwright-go v0.5001.0
- github.com/stretchr/testify v1.8.4
+ github.com/stretchr/testify v1.10.0
github.com/xlgmokha/x v0.0.0-20240605230110-5cbcac4d8ff8
golang.org/x/oauth2 v0.28.0
)
require (
+ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/arthurnn/twirp-ruby v1.13.0 // indirect
- github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
- github.com/casbin/govaluate v1.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set/v2 v2.7.0 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-stack/stack v1.8.1 // indirect
+ github.com/goccy/go-json v0.10.3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/jsonapi v1.0.0 // indirect
github.com/kr/text v0.2.0 // indirect
+ github.com/lestrrat-go/blackmagic v1.0.2 // indirect
+ github.com/lestrrat-go/httpcc v1.0.1 // indirect
+ github.com/lestrrat-go/httprc/v3 v3.0.0-beta1 // indirect
+ github.com/lestrrat-go/option v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/segmentio/asm v1.2.0 // indirect
+ golang.org/x/crypto v0.36.0 // indirect
+ golang.org/x/sys v0.31.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
go.sum
@@ -1,23 +1,23 @@
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/arthurnn/twirp-ruby v1.13.0 h1:j0T7I5oxe2niKFdfjiiCmkiydwYeegrbwVMs+Gajm6M=
github.com/arthurnn/twirp-ruby v1.13.0/go.mod h1:1fVOQuSLzwXoPi9/ejlDYG3roilJIPAZN2sw+A3o48o=
-github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
-github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
-github.com/casbin/casbin/v2 v2.103.0 h1:dHElatNXNrr8XcseUov0ZSiWjauwmZZE6YMV3eU1yic=
-github.com/casbin/casbin/v2 v2.103.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco=
-github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc=
-github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
+github.com/casbin/casbin/v3 v3.0.0-beta.7 h1:siS3e6cRtuyFlshUgJfw0wnWuK3z3U/ald0C8Jtof24=
+github.com/casbin/casbin/v3 v3.0.0-beta.7/go.mod h1:69HoI+h4yMUTydUMxT7VQh7FgGpoJsB/ZskkVGcvasQ=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusgcvJYW5k=
github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
-github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -30,6 +30,16 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
+github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
+github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
+github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
+github.com/lestrrat-go/httprc/v3 v3.0.0-beta1 h1:pzDjP9dSONCFQC/AE3mWUnHILGiYPiMKzQIS+weKJXA=
+github.com/lestrrat-go/httprc/v3 v3.0.0-beta1/go.mod h1:wdsgouffPvWPEYh8t7PRH/PidR5sfVqt0na4Nhj60Ms=
+github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3 h1:HHT8iW+UcPBgBr5A3soZQQsL5cBor/u6BkLB+wzY/R0=
+github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3/go.mod h1:ak32WoNtHE0aLowVWBcCvXngcAnW4tuC0YhFwOr/kwc=
+github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
+github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
@@ -42,19 +52,24 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
+github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xlgmokha/x v0.0.0-20240605230110-5cbcac4d8ff8 h1:Hmyf8pgNUs3l8TW0YdUarBVAU+hWX87efBukspg4nWc=
github.com/xlgmokha/x v0.0.0-20240605230110-5cbcac4d8ff8/go.mod h1:C9MUZ3A7PTPbrLNTvu2lKhpM0dFpPHt5yH8YGuYzmKQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
+golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -73,6 +88,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
+golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -85,7 +102,6 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
policy.csv
@@ -1,8 +1,11 @@
-p, "\A[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}\z", api.example.com, (GET)|(POST)|(PATCH)|(PUT)|(DELETE)|(HEAD), /*
+p, "\Agid:\/\/[a-z]+\/[A-Za-z:]+\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}\z", api.example.com, (GET)|(POST)|(PATCH)|(PUT)|(DELETE)|(HEAD), /*.json
p, *, *, (GET)|(HEAD), /health
p, *, *, GET, /.well-known/*
-p, *, idp.example.com, (GET)|(POST), /oauth/*
-p, *, idp.example.com, (GET)|(POST), /saml/*
-p, *, ui.example.com, (GET)|(POST), /oauth/*
-p, *, ui.example.com, (GET)|(POST), /saml/*
-p, 71cbc18e-bd41-4229-9ad2-749546a2a4a7, *, *, /*
+p, *, *, GET, /favicon.ico
+p, "\Agid:\/\/[a-z]+\/[A-Za-z:]+\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}\z", idp.example.com, (GET)|(POST)|(PATCH)|(PUT)|(DELETE)|(HEAD), /twirp/authx.rpc.*
+p, *, idp.example.com, (GET)|(POST), /oauth*
+p, *, idp.example.com, (GET)|(POST), /saml*
+p, *, idp.example.com, (GET)|(POST), /sessions*
+p, *, ui.example.com, (GET)|(POST), /oauth*
+p, *, ui.example.com, (GET)|(POST), /oidc*
+p, *, ui.example.com, (GET)|(POST), /saml*