feat/epic-48-replace-dex #20

Merged
faercol merged 20 commits from feat/epic-48-replace-dex into main 2024-10-27 15:16:40 +00:00
18 changed files with 334 additions and 49 deletions
Showing only changes of commit c71e7fa12f - Show all commits

View file

@ -2,6 +2,9 @@ package serve
import ( import (
"context" "context"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"log/slog" "log/slog"
"os" "os"
"os/signal" "os/signal"
@ -12,10 +15,12 @@ import (
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/client" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/client"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/middlewares" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/middlewares"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/storage" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/storage"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/server" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/server"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/services" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/services"
"github.com/go-jose/go-jose/v4"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/zitadel/oidc/v3/pkg/op" "github.com/zitadel/oidc/v3/pkg/op"
@ -53,9 +58,23 @@ func serve() {
} }
backends := map[uuid.UUID]*client.OIDCClient{} backends := map[uuid.UUID]*client.OIDCClient{}
key := sha256.Sum256([]byte("test"))
st := storage.Storage{LocalStorage: userDB, InitializedBackends: backends} privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
opConf := op.Config{} if err != nil {
utils.Failf("Failed to generate private key: %s", err)
}
signingKey := model.Key{
PrivateKey: privateKey,
KeyID: uuid.New(),
SigningAlg: jose.RS256,
}
st := storage.Storage{LocalStorage: userDB, InitializedBackends: backends, Key: &signingKey}
opConf := op.Config{
CryptoKey: key,
CodeMethodS256: false,
}
slogger := slog.New(zapslog.NewHandler(logger.L.Desugar().Core(), nil)) slogger := slog.New(zapslog.NewHandler(logger.L.Desugar().Core(), nil))
// slogger := // slogger :=
options := []op.Option{ options := []op.Option{

View file

@ -14,7 +14,7 @@ require (
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/zitadel/oidc/v3 v3.27.0 github.com/zitadel/oidc/v3 v3.30.1
go.uber.org/zap v1.24.0 go.uber.org/zap v1.24.0
go.uber.org/zap/exp v0.2.0 go.uber.org/zap/exp v0.2.0
) )
@ -68,25 +68,25 @@ require (
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect github.com/prometheus/procfs v0.11.1 // indirect
github.com/rs/cors v1.11.0 // indirect github.com/rs/cors v1.11.1 // indirect
github.com/russellhaering/goxmldsig v1.4.0 // indirect github.com/russellhaering/goxmldsig v1.4.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/zitadel/logging v0.6.0 // indirect github.com/zitadel/logging v0.6.1 // indirect
github.com/zitadel/schema v1.3.0 // indirect github.com/zitadel/schema v1.3.0 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.10.0 // indirect go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.25.0 // indirect golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
golang.org/x/net v0.26.0 // indirect golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.18.0 // indirect
google.golang.org/api v0.150.0 // indirect google.golang.org/api v0.150.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/grpc v1.59.0 // indirect google.golang.org/grpc v1.59.0 // indirect

View file

@ -177,8 +177,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys=
github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -210,20 +210,20 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank= github.com/zitadel/logging v0.6.1 h1:Vyzk1rl9Kq9RCevcpX6ujUaTYFX43aa4LkvV1TvUk+Y=
github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= github.com/zitadel/logging v0.6.1/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow=
github.com/zitadel/oidc/v3 v3.27.0 h1:zeYpyRH0UcgdCjVHUYzSsqf1jbSwVMPVxYKOnRXstgU= github.com/zitadel/oidc/v3 v3.30.1 h1:CCi9qDjleuRYbECfUoVKrrN97KdheNCHAs33X8XnIRg=
github.com/zitadel/oidc/v3 v3.27.0/go.mod h1:ZwBEqSviCpJVZiYashzo53bEGRGXi7amE5Q8PpQg9IM= github.com/zitadel/oidc/v3 v3.30.1/go.mod h1:N5p02vx+mLUwf+WFNpDsNp+8DS8+jlgFBwpz7NIQjrg=
github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0=
github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
@ -265,16 +265,16 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -303,8 +303,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

View file

@ -0,0 +1,62 @@
package authcode
import (
"context"
"database/sql"
"errors"
"fmt"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
)
var ErrNotFound = errors.New("auth code not found")
type AuthCodeDB interface {
GetAuthCodeByCode(ctx context.Context, code string) (*model.AuthCode, error)
CreateAuthCode(ctx context.Context, code model.AuthCode) error
}
type sqlAuthCodeDB struct {
db *sql.DB
}
func (db *sqlAuthCodeDB) CreateAuthCode(ctx context.Context, code model.AuthCode) error {
logger.L.Debugf("Creating auth code for request %s", code.RequestID)
tx, err := db.db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer func() { _ = tx.Rollback() }()
query := `INSERT INTO "auth_code_2" ("id", "auth_request_id", "code") VALUES ($1, $2, $3)`
_, err = tx.ExecContext(ctx, query, code.CodeID, code.RequestID, code.Code)
if err != nil {
return fmt.Errorf("failed to insert in DB: %w", err)
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func (db *sqlAuthCodeDB) GetAuthCodeByCode(ctx context.Context, code string) (*model.AuthCode, error) {
logger.L.Debugf("Getting auth code %s from DB", code)
query := `SELECT "id", "auth_request_id", "code" FROM "auth_code_2" WHERE "code" = ?`
row := db.db.QueryRowContext(ctx, query, code)
var res model.AuthCode
if err := row.Scan(&res.CodeID, &res.RequestID, &res.Code); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("failed to read row from DB: %w", err)
}
return &res, nil
}
func New(db *sql.DB) AuthCodeDB {
return &sqlAuthCodeDB{db: db}
}

View file

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"time"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
@ -14,12 +15,13 @@ import (
var ErrNotFound = errors.New("backend not found") var ErrNotFound = errors.New("backend not found")
const authRequestRows = `"id", "client_id", "backend_id", "scopes", "redirect_uri", "state", "nonce", "response_type", "creation_time", "done"` const authRequestRows = `"id", "client_id", "backend_id", "scopes", "redirect_uri", "state", "nonce", "response_type", "creation_time", "done", "code_challenge", "code_challenge_method", "auth_time"`
type AuthRequestDB interface { type AuthRequestDB interface {
GetAuthRequestByID(ctx context.Context, id uuid.UUID) (*model.AuthRequest, error) GetAuthRequestByID(ctx context.Context, id uuid.UUID) (*model.AuthRequest, error)
CreateAuthRequest(ctx context.Context, req model.AuthRequest) error CreateAuthRequest(ctx context.Context, req model.AuthRequest) error
ValidateAuthRequest(ctx context.Context, reqID uuid.UUID) error ValidateAuthRequest(ctx context.Context, reqID uuid.UUID) error
DeleteAuthRequest(ctx context.Context, reqID uuid.UUID) error
} }
type sqlAuthRequestDB struct { type sqlAuthRequestDB struct {
@ -34,10 +36,14 @@ func (db *sqlAuthRequestDB) GetAuthRequestByID(ctx context.Context, id uuid.UUID
var res model.AuthRequest var res model.AuthRequest
var scopesStr []byte var scopesStr []byte
fmt.Println(query) var timestamp *time.Time
if err := row.Scan(&res.ID, &res.ClientID, &res.BackendID, &scopesStr, &res.RedirectURI, &res.State, &res.Nonce, &res.ResponseType, &res.CreationDate, &res.DoneVal); err != nil {
if err := row.Scan(&res.ID, &res.ClientID, &res.BackendID, &scopesStr, &res.RedirectURI, &res.State, &res.Nonce, &res.ResponseType, &res.CreationDate, &res.DoneVal, &res.CodeChallenge, &res.CodeChallengeMethod, &timestamp); err != nil {
return nil, fmt.Errorf("failed to get auth request from DB: %w", err) return nil, fmt.Errorf("failed to get auth request from DB: %w", err)
} }
if timestamp != nil {
res.AuthTime = *timestamp
}
if err := json.Unmarshal(scopesStr, &res.Scopes); err != nil { if err := json.Unmarshal(scopesStr, &res.Scopes); err != nil {
return nil, fmt.Errorf("invalid format for scopes: %w", err) return nil, fmt.Errorf("invalid format for scopes: %w", err)
} }
@ -59,11 +65,12 @@ func (db *sqlAuthRequestDB) CreateAuthRequest(ctx context.Context, req model.Aut
} }
// TODO: when the old table is done, rename into auth_request // TODO: when the old table is done, rename into auth_request
query := fmt.Sprintf(`INSERT INTO "auth_request_2" (%s) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, authRequestRows) query := fmt.Sprintf(`INSERT INTO "auth_request_2" (%s) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NULL)`, authRequestRows)
_, err = tx.ExecContext(ctx, query, _, err = tx.ExecContext(ctx, query,
req.ID, req.ClientID, req.BackendID, req.ID, req.ClientID, req.BackendID,
scopesStr, req.RedirectURI, req.State, scopesStr, req.RedirectURI, req.State,
req.Nonce, req.ResponseType, req.CreationDate, false, req.Nonce, req.ResponseType, req.CreationDate, false,
req.CodeChallenge, req.CodeChallengeMethod,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to insert in DB: %w", err) return fmt.Errorf("failed to insert in DB: %w", err)
@ -84,7 +91,7 @@ func (db *sqlAuthRequestDB) ValidateAuthRequest(ctx context.Context, reqID uuid.
} }
defer func() { _ = tx.Rollback() }() defer func() { _ = tx.Rollback() }()
res, err := tx.ExecContext(ctx, `UPDATE "auth_request_2" SET done = true WHERE id = $1`, reqID.String()) res, err := tx.ExecContext(ctx, `UPDATE "auth_request_2" SET done = true, auth_time = $1 WHERE id = $2`, time.Now().UTC(), reqID.String())
if err != nil { if err != nil {
return fmt.Errorf("failed to update in DB: %w", err) return fmt.Errorf("failed to update in DB: %w", err)
} }
@ -103,6 +110,24 @@ func (db *sqlAuthRequestDB) ValidateAuthRequest(ctx context.Context, reqID uuid.
return nil return nil
} }
func (db *sqlAuthRequestDB) DeleteAuthRequest(ctx context.Context, reqID uuid.UUID) error {
logger.L.Debugf("Deleting auth request: %s", reqID)
tx, err := db.db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer func() { _ = tx.Rollback() }()
_, err = tx.ExecContext(ctx, `DELETE FROM "auth_request_2" WHERE id = $1`, reqID.String())
if err != nil {
return fmt.Errorf("failed to delete auth request: %w", err)
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func New(db *sql.DB) *sqlAuthRequestDB { func New(db *sql.DB) *sqlAuthRequestDB {
return &sqlAuthRequestDB{db: db} return &sqlAuthRequestDB{db: db}
} }

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/config" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/config"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/authcode"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/authrequest" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/authrequest"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/backend" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/backend"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/client" "git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/db/client"
@ -15,6 +16,7 @@ type Storage interface {
ClientStorage() client.ClientDB ClientStorage() client.ClientDB
BackendStorage() backend.BackendDB BackendStorage() backend.BackendDB
AuthRequestStorage() authrequest.AuthRequestDB AuthRequestStorage() authrequest.AuthRequestDB
AuthCodeStorage() authcode.AuthCodeDB
} }
type sqlStorage struct { type sqlStorage struct {
@ -37,6 +39,10 @@ func (s *sqlStorage) AuthRequestStorage() authrequest.AuthRequestDB {
return authrequest.New(s.db) return authrequest.New(s.db)
} }
func (s *sqlStorage) AuthCodeStorage() authcode.AuthCodeDB {
return authcode.New(s.db)
}
func New(conf config.AppConfig) (Storage, error) { func New(conf config.AppConfig) (Storage, error) {
db, err := sql.Open("sqlite3", conf.StorageConfig.File) db, err := sql.Open("sqlite3", conf.StorageConfig.File)
if err != nil { if err != nil {

View file

@ -0,0 +1,9 @@
package model
import "github.com/google/uuid"
type AuthCode struct {
CodeID uuid.UUID
RequestID uuid.UUID
Code string
}

View file

@ -56,7 +56,7 @@ func (a AuthRequest) GetAuthTime() time.Time {
} }
func (a AuthRequest) GetClientID() string { func (a AuthRequest) GetClientID() string {
return a.ID.String() // small hack since we actually need the AuthRequestID here return a.ClientID
} }
func (a AuthRequest) GetCodeChallenge() *oidc.CodeChallenge { func (a AuthRequest) GetCodeChallenge() *oidc.CodeChallenge {

View file

@ -39,7 +39,7 @@ func (c Client) ApplicationType() op.ApplicationType {
} }
func (c Client) AuthMethod() oidc.AuthMethod { func (c Client) AuthMethod() oidc.AuthMethod {
return oidc.AuthMethodNone return oidc.AuthMethodBasic
} }
func (c Client) ResponseTypes() []oidc.ResponseType { func (c Client) ResponseTypes() []oidc.ResponseType {
@ -47,13 +47,13 @@ func (c Client) ResponseTypes() []oidc.ResponseType {
} }
func (c Client) GrantTypes() []oidc.GrantType { func (c Client) GrantTypes() []oidc.GrantType {
return []oidc.GrantType{oidc.GrantTypeCode} return []oidc.GrantType{oidc.GrantTypeCode, oidc.GrantTypeRefreshToken, oidc.GrantTypeTokenExchange}
} }
// LoginURL returns the login URL for a given client app and auth request. // LoginURL returns the login URL for a given client app and auth request.
// This login url should be the authorization URL for the selected OIDC backend // This login url should be the authorization URL for the selected OIDC backend
func (c Client) LoginURL(authRequestID string) string { func (c Client) LoginURL(authRequestID string) string {
if c.AuthRequest == nil { if authRequestID == "" {
return "" // we don't have a request, let's return nothing return "" // we don't have a request, let's return nothing
} }

View file

@ -0,0 +1,57 @@
package model
import (
"crypto/rsa"
"strings"
"github.com/go-jose/go-jose/v4"
"github.com/google/uuid"
)
type SigningKey struct {
PrivateKey *rsa.PrivateKey
KeyID uuid.UUID
Algorithm jose.SignatureAlgorithm
}
func (k *SigningKey) ID() string {
return strings.ReplaceAll(k.KeyID.String(), "-", "")
}
func (k *SigningKey) SignatureAlgorithm() jose.SignatureAlgorithm {
return k.Algorithm
}
func (k *SigningKey) Key() any {
return k.PrivateKey
}
type Key struct {
PrivateKey *rsa.PrivateKey
KeyID uuid.UUID
SigningAlg jose.SignatureAlgorithm
}
func (k *Key) SigningKey() *SigningKey {
return &SigningKey{
PrivateKey: k.PrivateKey,
KeyID: k.KeyID,
Algorithm: k.SigningAlg,
}
}
func (k *Key) ID() string {
return strings.ReplaceAll(k.KeyID.String(), "-", "")
}
func (k *Key) Algorithm() jose.SignatureAlgorithm {
return k.SigningAlg
}
func (k *Key) Key() any {
return &k.PrivateKey.PublicKey
}
func (k *Key) Use() string {
return "sig"
}

View file

@ -0,0 +1,21 @@
package model
import (
"time"
"github.com/google/uuid"
)
type Token struct {
ID uuid.UUID
RefreshTokenID uuid.UUID
Expiration time.Time
Subjet string
Audiences []string
Scopes []string
}
type RefreshToken struct {
ID uuid.UUID
AuthTime time.Time
}

View file

@ -24,6 +24,7 @@ func ErrNotImplemented(name string) error {
type Storage struct { type Storage struct {
LocalStorage db.Storage LocalStorage db.Storage
InitializedBackends map[uuid.UUID]*client.OIDCClient InitializedBackends map[uuid.UUID]*client.OIDCClient
Key *model.Key
} }
/* /*
@ -33,7 +34,7 @@ func (s *Storage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest,
// userID should normally be an empty string (to verify), we don't get it in our workflow from what I saw // userID should normally be an empty string (to verify), we don't get it in our workflow from what I saw
// TODO: check this is indeed not needed / never present // TODO: check this is indeed not needed / never present
logger.L.Debug("Creating a new auth request") logger.L.Debugf("Creating a new auth request")
// validate that the connector is correct // validate that the connector is correct
backendName, ok := stringFromCtx(ctx, "backendName") backendName, ok := stringFromCtx(ctx, "backendName")
@ -69,24 +70,90 @@ func (s *Storage) AuthRequestByID(ctx context.Context, requestID string) (op.Aut
} }
func (s *Storage) AuthRequestByCode(ctx context.Context, requestCode string) (op.AuthRequest, error) { func (s *Storage) AuthRequestByCode(ctx context.Context, requestCode string) (op.AuthRequest, error) {
return nil, ErrNotImplemented("AuthRequestByCode") logger.L.Debugf("Getting auth request from code %s", requestCode)
authCode, err := s.LocalStorage.AuthCodeStorage().GetAuthCodeByCode(ctx, requestCode)
if err != nil {
return nil, fmt.Errorf("failed to get auth code from DB: %w", err)
}
return s.LocalStorage.AuthRequestStorage().GetAuthRequestByID(ctx, authCode.RequestID)
} }
func (s *Storage) SaveAuthCode(ctx context.Context, id string, code string) error { func (s *Storage) SaveAuthCode(ctx context.Context, id string, code string) error {
logger.L.Debugf("Saving auth code %s for request %s", code, id) logger.L.Debugf("Saving auth code %s for request %s", code, id)
return ErrNotImplemented("SaveAuthCode")
requestID, err := uuid.Parse(id)
if err != nil {
return fmt.Errorf("invalid requestID %s: %w", requestID, err)
}
codeID := uuid.New()
savedCode := model.AuthCode{
CodeID: codeID,
RequestID: requestID,
Code: code,
}
return s.LocalStorage.AuthCodeStorage().CreateAuthCode(ctx, savedCode)
} }
func (s *Storage) DeleteAuthRequest(ctx context.Context, id string) error { func (s *Storage) DeleteAuthRequest(ctx context.Context, id string) error {
return ErrNotImplemented("DeleteAuthRequest") return nil // don't delete it for now, it seems we might need it????? (cc dex)
// reqID, err := uuid.Parse(id)
// if err != nil {
// return fmt.Errorf("invalid id format: %w", err)
// }
// return s.LocalStorage.AuthRequestStorage().DeleteAuthRequest(ctx, reqID)
} }
func (s *Storage) CreateAccessToken(ctx context.Context, req op.TokenRequest) (accessTokenID string, expiration time.Time, err error) { func (s *Storage) CreateAccessToken(ctx context.Context, req op.TokenRequest) (accessTokenID string, expiration time.Time, err error) {
return "", time.Time{}, ErrNotImplemented("CreateAccessToken") accessTokenUUID := uuid.New()
// we are expecting our own request model
authRequest, ok := req.(*model.AuthRequest)
if !ok {
return "", time.Time{}, errors.New("failed to parse auth request")
}
authTime := authRequest.AuthTime.UTC()
expiration = authTime.Add(5 * time.Minute)
// token := model.Token{
// ID: accessTokenUUID,
// RefreshTokenID: refreshTokenUUID,
// Expiration: authTime.Add(5 * time.Minute),
// Subjet: request.GetSubject(),
// Audiences: request.GetAudience(),
// Scopes: request.GetScopes(),
// }
return accessTokenUUID.String(), expiration, nil
} }
func (s *Storage) CreateAccessAndRefreshTokens(ctx context.Context, request op.TokenRequest, currentRefreshToken string) (accessTokenID string, newRefreshTokenID string, expiration time.Time, err error) { func (s *Storage) CreateAccessAndRefreshTokens(ctx context.Context, request op.TokenRequest, currentRefreshToken string) (accessTokenID string, newRefreshTokenID string, expiration time.Time, err error) {
return "", "", time.Time{}, ErrNotImplemented("CreateAccessAndRefreshTokens") accessTokenUUID := uuid.New()
refreshTokenUUID := uuid.New()
// we are expecting our own request model
authRequest, ok := request.(*model.AuthRequest)
if !ok {
return "", "", time.Time{}, errors.New("failed to parse auth request")
}
authTime := authRequest.AuthTime.UTC()
expiration = authTime.Add(5 * time.Minute)
// token := model.Token{
// ID: accessTokenUUID,
// RefreshTokenID: refreshTokenUUID,
// Expiration: authTime.Add(5 * time.Minute),
// Subjet: request.GetSubject(),
// Audiences: request.GetAudience(),
// Scopes: request.GetScopes(),
// }
return accessTokenUUID.String(), refreshTokenUUID.String(), expiration, nil
} }
func (s *Storage) TokenRequestByRefreshToken(ctx context.Context, refreshTokenID string) (op.RefreshTokenRequest, error) { func (s *Storage) TokenRequestByRefreshToken(ctx context.Context, refreshTokenID string) (op.RefreshTokenRequest, error) {
@ -106,7 +173,7 @@ func (s *Storage) GetRefreshTokenInfo(ctx context.Context, clientID string, stok
} }
func (s *Storage) SigningKey(ctx context.Context) (op.SigningKey, error) { func (s *Storage) SigningKey(ctx context.Context) (op.SigningKey, error) {
return nil, ErrNotImplemented("SigningKey") return s.Key.SigningKey(), nil
} }
func (s *Storage) SignatureAlgorithms(ctx context.Context) ([]jose.SignatureAlgorithm, error) { func (s *Storage) SignatureAlgorithms(ctx context.Context) ([]jose.SignatureAlgorithm, error) {
@ -114,7 +181,7 @@ func (s *Storage) SignatureAlgorithms(ctx context.Context) ([]jose.SignatureAlgo
} }
func (s *Storage) KeySet(ctx context.Context) ([]op.Key, error) { func (s *Storage) KeySet(ctx context.Context) ([]op.Key, error) {
return nil, ErrNotImplemented("KeySet") return []op.Key{s.Key}, nil
} }
/* /*
@ -169,11 +236,23 @@ func (s *Storage) GetClientByClientID(ctx context.Context, id string) (op.Client
} }
func (s *Storage) AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string) error { func (s *Storage) AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string) error {
return ErrNotImplemented("AuthorizeClientIDSecret") logger.L.Debugf("Validating client secret %s for client %s", clientSecret, clientID)
client, err := s.LocalStorage.ClientStorage().GetClientByID(ctx, clientID)
if err != nil {
return err
}
if client.Secret != clientSecret {
return errors.New("invalid secret")
}
return nil
} }
func (s *Storage) SetUserinfoFromScopes(ctx context.Context, userinfo *oidc.UserInfo, userID, clientID string, scopes []string) error { func (s *Storage) SetUserinfoFromScopes(ctx context.Context, userinfo *oidc.UserInfo, userID, clientID string, scopes []string) error {
return ErrNotImplemented("SetUserinfoFromScopes") // we'll use FromRequest instead
return nil
} }
func (s *Storage) SetUserinfoFromToken(ctx context.Context, userinfo *oidc.UserInfo, tokenID, subject, origin string) error { func (s *Storage) SetUserinfoFromToken(ctx context.Context, userinfo *oidc.UserInfo, tokenID, subject, origin string) error {
@ -185,7 +264,8 @@ func (s *Storage) SetIntrospectionFromToken(ctx context.Context, userinfo *oidc.
} }
func (s *Storage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (map[string]interface{}, error) { func (s *Storage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (map[string]interface{}, error) {
return nil, ErrNotImplemented("GetPrivateClaimsFromScopes") // For now, let's just return nothing, we don't want to add any private scope
return nil, nil
} }
func (s *Storage) GetKeyByIDAndClientID(ctx context.Context, keyID, clientID string) (*jose.JSONWebKey, error) { func (s *Storage) GetKeyByIDAndClientID(ctx context.Context, keyID, clientID string) (*jose.JSONWebKey, error) {

View file

@ -7,5 +7,5 @@ CREATE TABLE "auth_request_2" (
state TEXT NOT NULL, state TEXT NOT NULL,
nonce TEXT NOT NULL, nonce TEXT NOT NULL,
response_type TEXT NOT NULL, response_type TEXT NOT NULL,
CREATION_TIME timestamp NOT NULL creation_time timestamp NOT NULL
); );

View file

@ -0,0 +1,2 @@
ALTER TABLE "auth_request_2" DROP COLUMN code_challenge;
ALTER TABLE "auth_request_2" DROP COLUMN code_challenge_method;

View file

@ -0,0 +1,2 @@
ALTER TABLE "auth_request_2" ADD COLUMN code_challenge STRING NOT NULL DEFAULT '';
ALTER TABLE "auth_request_2" ADD COLUMN code_challenge_method STRING NOT NULL DEFAULT '';

View file

@ -0,0 +1 @@
ALTER TABLE "auth_request_2" DROP COLUMN auth_time;

View file

@ -0,0 +1 @@
ALTER TABLE "auth_request_2" ADD COLUMN auth_time timestamp;

Binary file not shown.