From a6c18c4762cb62fe7a16cc32fd1aeed13df0b1bc Mon Sep 17 00:00:00 2001 From: Florian Hoss Date: Tue, 10 Sep 2024 19:46:16 +0200 Subject: [PATCH 1/3] zitadel --- go.mod | 29 +++++++++----- go.sum | 81 +++++++++++++++++++++++++++++---------- handlers/auth.handlers.go | 69 +++++++++++++++++++++++++++++++++ handlers/routes.go | 21 +++++++++- internal/env/env.go | 27 ++++++++----- main.go | 3 +- 6 files changed, 187 insertions(+), 43 deletions(-) create mode 100644 handlers/auth.handlers.go diff --git a/go.mod b/go.mod index e8d8817..d11fc23 100644 --- a/go.mod +++ b/go.mod @@ -3,37 +3,46 @@ module gitlab.unjx.de/flohoss/godash go 1.22 require ( - github.com/a-h/templ v0.2.747 + github.com/a-h/templ v0.2.778 github.com/caarlos0/env/v10 v10.0.0 - github.com/go-playground/validator/v10 v10.22.0 + github.com/go-playground/validator/v10 v10.22.1 + github.com/google/uuid v1.6.0 github.com/r3labs/sse/v2 v2.10.0 - github.com/shirou/gopsutil/v4 v4.24.7 - github.com/zitadel/oidc/v3 v3.28.1 + github.com/shirou/gopsutil/v4 v4.24.8 + github.com/zitadel/oidc/v3 v3.29.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/go-jose/go-jose/v4 v4.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 // indirect + github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect github.com/muhlemmer/gu v0.3.1 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect + github.com/zitadel/logging v0.6.0 // indirect github.com/zitadel/schema v1.3.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/go.sum b/go.sum index de452f1..2b07ce8 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,26 @@ -github.com/a-h/templ v0.2.707 h1:T1Gkd2ugbRglZ9rYw/VBchWOSZVKmetDbBkm4YubM7U= -github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8= github.com/a-h/templ v0.2.747 h1:D0dQ2lxC3W7Dxl6fxQ/1zZHBQslSkTSvl5FxP/CfdKg= github.com/a-h/templ v0.2.747/go.mod h1:69ObQIbrcuwPCU32ohNaWce3Cb7qM5GMiqN1K+2yop4= +github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM= +github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +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/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= 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/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= -github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -23,13 +30,20 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.21.0 h1:4fZA11ovvtkdgaeev9RGWPgc1uj3H8W+rNYyH/ySBb0= -github.com/go-playground/validator/v10 v10.21.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= +github.com/jeremija/gosubmit v0.2.7/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -39,17 +53,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY= github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= +github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0= +github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= +github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= +github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= @@ -57,14 +71,19 @@ github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktE github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/shirou/gopsutil/v4 v4.24.5 h1:gGsArG5K6vmsh5hcFOHaPm87UD003CaDMkAOweSQjhM= -github.com/shirou/gopsutil/v4 v4.24.5/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= +github.com/shirou/gopsutil/v4 v4.24.8 h1:pVQjIenQkIhqO81mwTaXjTzOMT7d3TZkf43PlVFHENI= +github.com/shirou/gopsutil/v4 v4.24.8/go.mod h1:wE0OrJtj4dG+hYkxqDH3QiBICdKSf04/npcvLLc/oRg= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -75,39 +94,61 @@ github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYg github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank= +github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= github.com/zitadel/oidc/v3 v3.28.1 h1:PsbFm5CzEMQq9HBXUNJ8yvnWmtVYxpwV5Cinj7TTsHo= github.com/zitadel/oidc/v3 v3.28.1/go.mod h1:WmDFu3dZ9YNKrIoZkmxjGG8QyUR4PbbhsVVSY+rpojM= +github.com/zitadel/oidc/v3 v3.29.0 h1:pzpELMr2TM2AzGsDVJ9TRQvNVoiEfda6NUeuL0y6R5g= +github.com/zitadel/oidc/v3 v3.29.0/go.mod h1:8TCcN+ClFcWq0DIQilzp0pssdA+8TC5rZ6wzNozrdG8= github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +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.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +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.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/auth.handlers.go b/handlers/auth.handlers.go new file mode 100644 index 0000000..d013fea --- /dev/null +++ b/handlers/auth.handlers.go @@ -0,0 +1,69 @@ +package handlers + +import ( + "context" + "encoding/json" + "log/slog" + "net/http" + "os" + "time" + + "github.com/zitadel/oidc/v3/pkg/client/rp" + httphelper "github.com/zitadel/oidc/v3/pkg/http" + "github.com/zitadel/oidc/v3/pkg/oidc" + + "gitlab.unjx.de/flohoss/godash/internal/env" +) + +func NewAuthHandler(env *env.Config) *AuthHandler { + key := []byte(env.SessionKey) + cookieHandler := httphelper.NewCookieHandler(key, key, httphelper.WithUnsecure()) + client := &http.Client{ + Timeout: time.Minute, + } + + options := []rp.Option{ + rp.WithCookieHandler(cookieHandler), + rp.WithVerifierOpts(rp.WithIssuedAtOffset(5 * time.Second)), + rp.WithHTTPClient(client), + rp.WithSigningAlgsFromDiscovery(), + rp.WithPKCE(cookieHandler), + } + + ctx := context.Background() + provider, err := rp.NewRelyingPartyOIDC(ctx, env.OIDCIssuer, env.OIDCClientID, env.OIDCClientSecret, env.OIDCRedirectURI, env.OIDCScopes, options...) + if err != nil { + slog.Error("error creating provider", "err", err.Error()) + os.Exit(1) + } + + urlOptions := []rp.URLParamOpt{} + if env.OIDCResponseMode != "" { + urlOptions = append(urlOptions, rp.WithResponseModeURLParam(oidc.ResponseMode(env.OIDCResponseMode))) + } + + marshalToken := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens[*oidc.IDTokenClaims], state string, rp rp.RelyingParty) { + data, err := json.Marshal(tokens) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Write(data) + } + + return &AuthHandler{ + env: env, + provider: provider, + options: options, + urlOptions: urlOptions, + marshalToken: marshalToken, + } +} + +type AuthHandler struct { + env *env.Config + provider rp.RelyingParty + options []rp.Option + urlOptions []rp.URLParamOpt + marshalToken func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens[*oidc.IDTokenClaims], state string, rp rp.RelyingParty) +} diff --git a/handlers/routes.go b/handlers/routes.go index b84a0a4..81bf1d6 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -1,12 +1,15 @@ package handlers import ( + "context" "net/http" + "github.com/google/uuid" "github.com/r3labs/sse/v2" + "github.com/zitadel/oidc/v3/pkg/client/rp" ) -func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler) { +func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler, authHandler *AuthHandler) { router.HandleFunc("GET /sse", sse.ServeHTTP) fsAssets := http.FileServer(http.Dir("assets")) @@ -15,5 +18,19 @@ func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler) icons := http.FileServer(http.Dir("storage/icons")) router.Handle("GET /icons/", http.StripPrefix("/icons/", icons)) - router.HandleFunc("GET /", appHandler.appHandler) + state := func() string { + return uuid.New().String() + } + router.Handle("GET /login", rp.AuthURLHandler(state, authHandler.provider, authHandler.urlOptions...)) + router.Handle("GET /auch/callback", rp.CodeExchangeHandler(authHandler.marshalToken, authHandler.provider)) + + router.HandleFunc("GET /", authMiddleware(http.HandlerFunc(appHandler.appHandler), authHandler)) +} + +func authMiddleware(next http.Handler, authHandler *AuthHandler) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + clains, err := rp.VerifyTokens(ctx, authHandler.provider) + next.ServeHTTP(w, r) + } } diff --git a/internal/env/env.go b/internal/env/env.go index 9a01257..bf3ea5c 100644 --- a/internal/env/env.go +++ b/internal/env/env.go @@ -8,16 +8,23 @@ import ( ) type Config struct { - TimeZone string `env:"TZ" envDefault:"Etc/UTC" validate:"timezone"` - Title string `env:"TITLE" envDefault:"goDash"` - Port int `env:"PORT" envDefault:"4000" validate:"min=1024,max=49151"` - Version string `env:"APP_VERSION"` - LocationLatitude float32 `env:"LOCATION_LATITUDE" envDefault:"48.780331609463815" validate:"latitude"` - LocationLongitude float32 `env:"LOCATION_LONGITUDE" envDefault:"9.177968320179422" validate:"longitude"` - WeatherKey string `env:"WEATHER_KEY"` - WeatherUnits string `env:"WEATHER_UNITS" envDefault:"metric"` - WeatherLanguage string `env:"WEATHER_LANG" envDefault:"en" validate:"bcp47_language_tag"` - WeatherDigits bool `env:"WEATHER_DIGITS" envDefault:"false"` + TimeZone string `env:"TZ" envDefault:"Etc/UTC" validate:"timezone"` + Title string `env:"TITLE" envDefault:"goDash"` + Port int `env:"PORT" envDefault:"4000" validate:"min=1024,max=49151"` + Version string `env:"APP_VERSION"` + LocationLatitude float32 `env:"LOCATION_LATITUDE" envDefault:"48.780331609463815" validate:"latitude"` + LocationLongitude float32 `env:"LOCATION_LONGITUDE" envDefault:"9.177968320179422" validate:"longitude"` + WeatherKey string `env:"WEATHER_KEY"` + WeatherUnits string `env:"WEATHER_UNITS" envDefault:"metric"` + WeatherLanguage string `env:"WEATHER_LANG" envDefault:"en" validate:"bcp47_language_tag"` + WeatherDigits bool `env:"WEATHER_DIGITS" envDefault:"false"` + OIDCClientID string `env:"OIDC_CLIENT_ID"` + OIDCClientSecret string `env:"OIDC_CLIENT_SECRET"` + OIDCRedirectURI string `env:"OIDC_REDIRECT_URI"` + OIDCScopes []string `env:"OIDC_SCOPES" envSeparator:"," envDefault:"openid,email,profile"` + OIDCIssuer string `env:"OIDC_ISSUER"` + OIDCResponseMode string `env:"OIDC_RESPONSE_MODE"` + SessionKey string `env:"SESSION_KEY,unset"` } var errParse = errors.New("error parsing environment variables") diff --git a/main.go b/main.go index fde344c..150a715 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,8 @@ func main() { b := services.NewBookmarkService() appHandler := handlers.NewAppHandler(env, s, w, b) - handlers.SetupRoutes(router, sse, appHandler) + authHandler := handlers.NewAuthHandler(env) + handlers.SetupRoutes(router, sse, appHandler, authHandler) lis := fmt.Sprintf(":%d", env.Port) slog.Info("server listening, press ctrl+c to stop", "addr", "http://localhost"+lis) From 34486a6ca42b381b305f8f6a744d45536e5dae4d Mon Sep 17 00:00:00 2001 From: Florian Hoss Date: Mon, 16 Sep 2024 06:55:39 +0200 Subject: [PATCH 2/3] Remove zitadel for oauth2 package --- .vscode/launch.json | 37 +++++--- go.mod | 15 +--- go.sum | 69 +-------------- handlers/auth.handlers.go | 174 ++++++++++++++++++++++++++++++-------- handlers/routes.go | 20 +---- 5 files changed, 169 insertions(+), 146 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index cf198a1..8db3887 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,13 +1,26 @@ { - "version": "0.2.0", - "configurations": [ - { - "name": "Debug golang", - "type": "go", - "request": "attach", - "mode": "remote", - "port": 4001, - "host": "127.0.0.1" - } - ] -} + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "env": { + "TITLE": "DEV", + "PUBLIC_URL": "http://localhost:4000", + "WEATHER_KEY": "3722ce75e9330aaefde1cb3eb1b8b030", + "APP_VERSION": "v0.0.1-DEV", + "OIDC_CLIENT_ID": "home", + "OIDC_CLIENT_SECRET": "PkfS5S7BkiEeqX3Km7BGxsBrmH6MOzjqcpODTz2akxMCMFHv8TAvIfyWgTlKof85", + "OIDC_REDIRECT_URI": "http://localhost:4000/auth/callback", + "OIDC_ISSUER": "https://sso.unjx.de/auth/v1", + "SESSION_KEY": "49cda749cb5eaa6c38f371c530808ca8", + } + } + ] +} \ No newline at end of file diff --git a/go.mod b/go.mod index d11fc23..cce7c1e 100644 --- a/go.mod +++ b/go.mod @@ -5,42 +5,31 @@ go 1.22 require ( github.com/a-h/templ v0.2.778 github.com/caarlos0/env/v10 v10.0.0 + github.com/coreos/go-oidc/v3 v3.11.0 github.com/go-playground/validator/v10 v10.22.1 - github.com/google/uuid v1.6.0 github.com/r3labs/sse/v2 v2.10.0 github.com/shirou/gopsutil/v4 v4.24.8 - github.com/zitadel/oidc/v3 v3.29.0 + golang.org/x/oauth2 v0.23.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/go-jose/go-jose/v4 v4.0.4 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/gorilla/securecookie v1.1.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect - github.com/muhlemmer/gu v0.3.1 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zitadel/logging v0.6.0 // indirect - github.com/zitadel/schema v1.3.0 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect diff --git a/go.sum b/go.sum index 2b07ce8..bdeac65 100644 --- a/go.sum +++ b/go.sum @@ -1,26 +1,17 @@ -github.com/a-h/templ v0.2.747 h1:D0dQ2lxC3W7Dxl6fxQ/1zZHBQslSkTSvl5FxP/CfdKg= -github.com/a-h/templ v0.2.747/go.mod h1:69ObQIbrcuwPCU32ohNaWce3Cb7qM5GMiqN1K+2yop4= github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM= github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= -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/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= 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/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -30,20 +21,10 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= -github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= -github.com/jeremija/gosubmit v0.2.7/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -53,14 +34,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY= -github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0= github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= -github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= -github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= -github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= -github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -71,19 +46,12 @@ github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktE github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= -github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= -github.com/shirou/gopsutil/v4 v4.24.7 h1:V9UGTK4gQ8HvcnPKf6Zt3XHyQq/peaekfxpJ2HSocJk= -github.com/shirou/gopsutil/v4 v4.24.7/go.mod h1:0uW/073rP7FYLOkvxolUQM5rMOLTNmRXnFKafpb71rw= github.com/shirou/gopsutil/v4 v4.24.8 h1:pVQjIenQkIhqO81mwTaXjTzOMT7d3TZkf43PlVFHENI= github.com/shirou/gopsutil/v4 v4.24.8/go.mod h1:wE0OrJtj4dG+hYkxqDH3QiBICdKSf04/npcvLLc/oRg= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -94,52 +62,21 @@ github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYg github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank= -github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= -github.com/zitadel/oidc/v3 v3.28.1 h1:PsbFm5CzEMQq9HBXUNJ8yvnWmtVYxpwV5Cinj7TTsHo= -github.com/zitadel/oidc/v3 v3.28.1/go.mod h1:WmDFu3dZ9YNKrIoZkmxjGG8QyUR4PbbhsVVSY+rpojM= -github.com/zitadel/oidc/v3 v3.29.0 h1:pzpELMr2TM2AzGsDVJ9TRQvNVoiEfda6NUeuL0y6R5g= -github.com/zitadel/oidc/v3 v3.29.0/go.mod h1:8TCcN+ClFcWq0DIQilzp0pssdA+8TC5rZ6wzNozrdG8= -github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= -github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -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.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -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.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= @@ -147,8 +84,6 @@ gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UD gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/auth.handlers.go b/handlers/auth.handlers.go index d013fea..33944b1 100644 --- a/handlers/auth.handlers.go +++ b/handlers/auth.handlers.go @@ -2,68 +2,168 @@ package handlers import ( "context" + "crypto/rand" + "crypto/sha256" + "encoding/base64" "encoding/json" + "fmt" + "io" "log/slog" "net/http" "os" "time" - "github.com/zitadel/oidc/v3/pkg/client/rp" - httphelper "github.com/zitadel/oidc/v3/pkg/http" - "github.com/zitadel/oidc/v3/pkg/oidc" + "github.com/coreos/go-oidc/v3/oidc" + "golang.org/x/oauth2" "gitlab.unjx.de/flohoss/godash/internal/env" ) -func NewAuthHandler(env *env.Config) *AuthHandler { - key := []byte(env.SessionKey) - cookieHandler := httphelper.NewCookieHandler(key, key, httphelper.WithUnsecure()) - client := &http.Client{ - Timeout: time.Minute, +func randString(nByte int) (string, error) { + b := make([]byte, nByte) + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return "", err } + return base64.RawURLEncoding.EncodeToString(b), nil +} - options := []rp.Option{ - rp.WithCookieHandler(cookieHandler), - rp.WithVerifierOpts(rp.WithIssuedAtOffset(5 * time.Second)), - rp.WithHTTPClient(client), - rp.WithSigningAlgsFromDiscovery(), - rp.WithPKCE(cookieHandler), +func setCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) { + c := &http.Cookie{ + Name: name, + Value: value, + MaxAge: int(time.Hour.Seconds()), + Secure: r.TLS != nil, + HttpOnly: true, } + http.SetCookie(w, c) +} - ctx := context.Background() - provider, err := rp.NewRelyingPartyOIDC(ctx, env.OIDCIssuer, env.OIDCClientID, env.OIDCClientSecret, env.OIDCRedirectURI, env.OIDCScopes, options...) +func generateCodeVerifier() (string, error) { + verifierLength := 64 + verifier := make([]byte, verifierLength) + + _, err := rand.Read(verifier) if err != nil { - slog.Error("error creating provider", "err", err.Error()) + return "", err + } + return base64.RawURLEncoding.EncodeToString(verifier), nil +} + +func generateCodeChallenge(verifier string) string { + hash := sha256.New() + _, _ = io.WriteString(hash, verifier) + sha := hash.Sum(nil) + return base64.RawURLEncoding.EncodeToString(sha) +} + +func NewAuthHandler(env *env.Config) *AuthHandler { + ctx := context.Background() + + oidcProvider, err := oidc.NewProvider(ctx, env.OIDCIssuer) + if err != nil { + slog.Error("Failed to get oidc provider", "err", err.Error()) os.Exit(1) } - urlOptions := []rp.URLParamOpt{} - if env.OIDCResponseMode != "" { - urlOptions = append(urlOptions, rp.WithResponseModeURLParam(oidc.ResponseMode(env.OIDCResponseMode))) + oauth2Config := &oauth2.Config{ + ClientID: env.OIDCClientID, + ClientSecret: env.OIDCClientSecret, + Endpoint: oidcProvider.Endpoint(), + RedirectURL: env.OIDCRedirectURI, + Scopes: env.OIDCScopes, } - marshalToken := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens[*oidc.IDTokenClaims], state string, rp rp.RelyingParty) { - data, err := json.Marshal(tokens) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.Write(data) + codeVerifier, err := generateCodeVerifier() + if err != nil { + slog.Error("Error generating code verifier", "err", err.Error()) + os.Exit(1) + } + codeChallenge := generateCodeChallenge(codeVerifier) + authCodeOptions := []oauth2.AuthCodeOption{ + oauth2.SetAuthURLParam("code_challenge", codeChallenge), + oauth2.SetAuthURLParam("code_challenge_method", "S256"), } return &AuthHandler{ - env: env, - provider: provider, - options: options, - urlOptions: urlOptions, - marshalToken: marshalToken, + ctx: ctx, + oidcProvider: oidcProvider, + oauth2Config: oauth2Config, + authCodeOptions: authCodeOptions, } } type AuthHandler struct { - env *env.Config - provider rp.RelyingParty - options []rp.Option - urlOptions []rp.URLParamOpt - marshalToken func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens[*oidc.IDTokenClaims], state string, rp rp.RelyingParty) + ctx context.Context + oidcProvider *oidc.Provider + oauth2Config *oauth2.Config + authCodeOptions []oauth2.AuthCodeOption +} + +func (ah *AuthHandler) handleAuth(w http.ResponseWriter, r *http.Request) { + state, err := randString(16) + if err != nil { + http.Error(w, "Internal error", http.StatusInternalServerError) + return + } + setCallbackCookie(w, r, "state", state) + + http.Redirect(w, r, ah.oauth2Config.AuthCodeURL(state, ah.authCodeOptions...), http.StatusFound) +} + +func (ah *AuthHandler) handleCallback(w http.ResponseWriter, r *http.Request) { + state, err := r.Cookie("state") + if err != nil { + http.Error(w, "state not found", http.StatusBadRequest) + return + } + if r.URL.Query().Get("state") != state.Value { + http.Error(w, "state did not match", http.StatusBadRequest) + return + } + + oauth2Token, err := ah.oauth2Config.Exchange(ah.ctx, r.URL.Query().Get("code")) + if err != nil { + http.Error(w, "failed to exchange token: "+err.Error(), http.StatusInternalServerError) + return + } + + userInfo, err := ah.oidcProvider.UserInfo(ah.ctx, oauth2.StaticTokenSource(oauth2Token)) + if err != nil { + http.Error(w, "failed to get userinfo: "+err.Error(), http.StatusInternalServerError) + return + } + + resp := struct { + OAuth2Token *oauth2.Token + UserInfo *oidc.UserInfo + }{oauth2Token, userInfo} + data, err := json.MarshalIndent(resp, "", " ") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Write(data) +} + +func (ah *AuthHandler) AuthMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + state, err := r.Cookie("state") + if err != nil { + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + oauth2Token, err := ah.oauth2Config.Exchange(ah.ctx, r.URL.Query().Get("code")) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + userInfo, err := ah.oidcProvider.UserInfo(ah.ctx, oauth2.StaticTokenSource(oauth2Token)) + if err != nil { + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + fmt.Println(userInfo) + next.ServeHTTP(w, r) + }) } diff --git a/handlers/routes.go b/handlers/routes.go index 81bf1d6..fe57f5f 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -1,12 +1,9 @@ package handlers import ( - "context" "net/http" - "github.com/google/uuid" "github.com/r3labs/sse/v2" - "github.com/zitadel/oidc/v3/pkg/client/rp" ) func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler, authHandler *AuthHandler) { @@ -18,19 +15,8 @@ func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler, icons := http.FileServer(http.Dir("storage/icons")) router.Handle("GET /icons/", http.StripPrefix("/icons/", icons)) - state := func() string { - return uuid.New().String() - } - router.Handle("GET /login", rp.AuthURLHandler(state, authHandler.provider, authHandler.urlOptions...)) - router.Handle("GET /auch/callback", rp.CodeExchangeHandler(authHandler.marshalToken, authHandler.provider)) + router.HandleFunc("GET /login", authHandler.handleAuth) + router.HandleFunc("GET /auch/callback", authHandler.handleCallback) - router.HandleFunc("GET /", authMiddleware(http.HandlerFunc(appHandler.appHandler), authHandler)) -} - -func authMiddleware(next http.Handler, authHandler *AuthHandler) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - ctx := context.Background() - clains, err := rp.VerifyTokens(ctx, authHandler.provider) - next.ServeHTTP(w, r) - } + router.Handle("GET /", authHandler.AuthMiddleware(http.HandlerFunc(appHandler.appHandler))) } From 00915c67d7fefb0f3564b3b3a94927f96377741d Mon Sep 17 00:00:00 2001 From: Florian Hoss Date: Mon, 16 Sep 2024 11:45:24 +0200 Subject: [PATCH 3/3] Add auth --- components/application.templ | 4 +- components/system.templ | 14 +++--- components/user.templ | 11 +++++ components/weather.templ | 2 +- go.mod | 2 + go.sum | 4 ++ handlers/app.handlers.go | 13 +++--- handlers/auth.handlers.go | 82 +++++++++++++++--------------------- handlers/routes.go | 10 ++--- main.go | 2 +- services/claims.services.go | 71 +++++++++++++++++++++++++++++++ views/home/home.templ | 14 +++--- 12 files changed, 152 insertions(+), 77 deletions(-) create mode 100644 components/user.templ create mode 100644 services/claims.services.go diff --git a/components/application.templ b/components/application.templ index 2f72b67..9a0efa6 100644 --- a/components/application.templ +++ b/components/application.templ @@ -1,8 +1,6 @@ package components -import ( - "gitlab.unjx.de/flohoss/godash/services" -) +import "gitlab.unjx.de/flohoss/godash/services" templ Application(application services.Application) { diff --git a/components/system.templ b/components/system.templ index 76e1c6a..2600e1e 100644 --- a/components/system.templ +++ b/components/system.templ @@ -1,9 +1,9 @@ package components import ( - "html/template" - "gitlab.unjx.de/flohoss/godash/services" "fmt" + "gitlab.unjx.de/flohoss/godash/services" + "html/template" ) var BarTemplate = template.Must(template.New("bar").Parse("
")) @@ -20,7 +20,7 @@ templ System(icon string, infoPre string, infoPost string, extraInfo string, per
{ extraInfo }
{ infoPre }{ infoPost }
- @templ.FromGoHTML(BarTemplate, Bar{Id:percentageId, Percentage:percentage}) + @templ.FromGoHTML(BarTemplate, Bar{Id: percentageId, Percentage: percentage})
@@ -42,18 +42,18 @@ templ Uptime(extraInfo string, id string, uptime services.Uptime) {
{ fmt.Sprintf("%d",uptime.Days) } days - @templ.FromGoHTML(countDownTemplate, Countdown{Id:"uptimeHours", Value:uptime.Hours}) + @templ.FromGoHTML(countDownTemplate, Countdown{Id: "uptimeHours", Value: uptime.Hours}) hours - @templ.FromGoHTML(countDownTemplate, Countdown{Id:"uptimeMinutes", Value:uptime.Minutes}) + @templ.FromGoHTML(countDownTemplate, Countdown{Id: "uptimeMinutes", Value: uptime.Minutes}) min - @templ.FromGoHTML(countDownTemplate, Countdown{Id:"uptimeSeconds", Value:uptime.Seconds}) + @templ.FromGoHTML(countDownTemplate, Countdown{Id: "uptimeSeconds", Value: uptime.Seconds}) sec
- @templ.FromGoHTML(BarTemplate, Bar{Id:id, Percentage:float64(uptime.Percentage)}) + @templ.FromGoHTML(BarTemplate, Bar{Id: id, Percentage: float64(uptime.Percentage)})
diff --git a/components/user.templ b/components/user.templ new file mode 100644 index 0000000..26ef43d --- /dev/null +++ b/components/user.templ @@ -0,0 +1,11 @@ +package components + +import "gitlab.unjx.de/flohoss/godash/services" + +templ User(user services.User) { +
+
+ +
+
+} diff --git a/components/weather.templ b/components/weather.templ index d2c350b..8234483 100644 --- a/components/weather.templ +++ b/components/weather.templ @@ -1,8 +1,8 @@ package components import ( - "gitlab.unjx.de/flohoss/godash/services" "fmt" + "gitlab.unjx.de/flohoss/godash/services" ) func getIcon(icon string) string { diff --git a/go.mod b/go.mod index cce7c1e..d498b24 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,13 @@ go 1.22 require ( github.com/a-h/templ v0.2.778 + github.com/alexedwards/scs/v2 v2.8.0 github.com/caarlos0/env/v10 v10.0.0 github.com/coreos/go-oidc/v3 v3.11.0 github.com/go-playground/validator/v10 v10.22.1 github.com/r3labs/sse/v2 v2.10.0 github.com/shirou/gopsutil/v4 v4.24.8 + github.com/thanhpk/randstr v1.0.6 golang.org/x/oauth2 v0.23.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index bdeac65..771e896 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM= github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= +github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= @@ -56,6 +58,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o= +github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= diff --git a/handlers/app.handlers.go b/handlers/app.handlers.go index 368ece3..5ca2c05 100644 --- a/handlers/app.handlers.go +++ b/handlers/app.handlers.go @@ -38,10 +38,6 @@ type AppHandler struct { } func (bh *AppHandler) appHandler(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/" { - http.Redirect(w, r, "/", http.StatusFound) - return - } bookmarks := bh.bookmarkService.GetAllBookmarks() staticSystem := bh.systemService.GetStaticInformation() liveSystem := bh.systemService.GetLiveInformation() @@ -49,5 +45,12 @@ func (bh *AppHandler) appHandler(w http.ResponseWriter, r *http.Request) { titlePage := bh.env.Title - home.HomeIndex(titlePage, bh.env.Version, home.Home(titlePage, bookmarks, staticSystem, liveSystem, weather)).Render(r.Context(), w) + user := services.User{ + Name: w.Header().Get("X-User-Name"), + Email: w.Header().Get("X-User-Email"), + } + gravatar := services.NewGravatarFromEmail(user.Email) + user.Gravatar = gravatar.GetURL() + + home.HomeIndex(titlePage, bh.env.Version, home.Home(titlePage, user, bookmarks, staticSystem, liveSystem, weather)).Render(r.Context(), w) } diff --git a/handlers/auth.handlers.go b/handlers/auth.handlers.go index 33944b1..dbf6096 100644 --- a/handlers/auth.handlers.go +++ b/handlers/auth.handlers.go @@ -5,28 +5,21 @@ import ( "crypto/rand" "crypto/sha256" "encoding/base64" - "encoding/json" - "fmt" "io" "log/slog" "net/http" "os" "time" + "github.com/alexedwards/scs/v2" "github.com/coreos/go-oidc/v3/oidc" + "github.com/thanhpk/randstr" "golang.org/x/oauth2" "gitlab.unjx.de/flohoss/godash/internal/env" + "gitlab.unjx.de/flohoss/godash/services" ) -func randString(nByte int) (string, error) { - b := make([]byte, nByte) - if _, err := io.ReadFull(rand.Reader, b); err != nil { - return "", err - } - return base64.RawURLEncoding.EncodeToString(b), nil -} - func setCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) { c := &http.Cookie{ Name: name, @@ -80,15 +73,21 @@ func NewAuthHandler(env *env.Config) *AuthHandler { } codeChallenge := generateCodeChallenge(codeVerifier) authCodeOptions := []oauth2.AuthCodeOption{ + oauth2.SetAuthURLParam("redirect_uri", env.OIDCRedirectURI), oauth2.SetAuthURLParam("code_challenge", codeChallenge), oauth2.SetAuthURLParam("code_challenge_method", "S256"), + oauth2.SetAuthURLParam("code_verifier", codeVerifier), } + sessionManager := scs.New() + sessionManager.Lifetime = 24 * time.Hour + return &AuthHandler{ ctx: ctx, oidcProvider: oidcProvider, oauth2Config: oauth2Config, authCodeOptions: authCodeOptions, + SessionManager: sessionManager, } } @@ -97,17 +96,7 @@ type AuthHandler struct { oidcProvider *oidc.Provider oauth2Config *oauth2.Config authCodeOptions []oauth2.AuthCodeOption -} - -func (ah *AuthHandler) handleAuth(w http.ResponseWriter, r *http.Request) { - state, err := randString(16) - if err != nil { - http.Error(w, "Internal error", http.StatusInternalServerError) - return - } - setCallbackCookie(w, r, "state", state) - - http.Redirect(w, r, ah.oauth2Config.AuthCodeURL(state, ah.authCodeOptions...), http.StatusFound) + SessionManager *scs.SessionManager } func (ah *AuthHandler) handleCallback(w http.ResponseWriter, r *http.Request) { @@ -121,49 +110,46 @@ func (ah *AuthHandler) handleCallback(w http.ResponseWriter, r *http.Request) { return } - oauth2Token, err := ah.oauth2Config.Exchange(ah.ctx, r.URL.Query().Get("code")) + oauth2Token, err := ah.oauth2Config.Exchange(ah.ctx, r.URL.Query().Get("code"), ah.authCodeOptions...) if err != nil { http.Error(w, "failed to exchange token: "+err.Error(), http.StatusInternalServerError) return } - userInfo, err := ah.oidcProvider.UserInfo(ah.ctx, oauth2.StaticTokenSource(oauth2Token)) - if err != nil { - http.Error(w, "failed to get userinfo: "+err.Error(), http.StatusInternalServerError) - return - } + ah.SessionManager.Put(r.Context(), "access_token", oauth2Token.AccessToken) - resp := struct { - OAuth2Token *oauth2.Token - UserInfo *oidc.UserInfo - }{oauth2Token, userInfo} - data, err := json.MarshalIndent(resp, "", " ") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.Write(data) + http.Redirect(w, r, "/", http.StatusFound) +} + +func (ah *AuthHandler) handleLogout(w http.ResponseWriter, r *http.Request) { + ah.SessionManager.Clear(r.Context()) + http.Redirect(w, r, "/", http.StatusFound) +} + +func (ah *AuthHandler) handleLogin(w http.ResponseWriter, r *http.Request) { + state := randstr.String(16) + setCallbackCookie(w, r, "state", state) + http.Redirect(w, r, ah.oauth2Config.AuthCodeURL(state, ah.authCodeOptions...), http.StatusFound) } func (ah *AuthHandler) AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - state, err := r.Cookie("state") - if err != nil { - http.Error(w, err.Error(), http.StatusUnauthorized) - return - } - oauth2Token, err := ah.oauth2Config.Exchange(ah.ctx, r.URL.Query().Get("code")) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + accessToken := ah.SessionManager.GetString(r.Context(), "access_token") + if accessToken == "" { + ah.handleLogin(w, r) return } - userInfo, err := ah.oidcProvider.UserInfo(ah.ctx, oauth2.StaticTokenSource(oauth2Token)) + userInfo, err := ah.oidcProvider.UserInfo(ah.ctx, oauth2.StaticTokenSource(&oauth2.Token{AccessToken: accessToken})) if err != nil { - http.Error(w, err.Error(), http.StatusUnauthorized) + ah.handleLogin(w, r) return } - fmt.Println(userInfo) + var userClaims services.User + userInfo.Claims(&userClaims) + w.Header().Set("X-User-Name", userClaims.Name) + w.Header().Set("X-User-Email", userClaims.Email) + next.ServeHTTP(w, r) }) } diff --git a/handlers/routes.go b/handlers/routes.go index fe57f5f..1bce187 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -7,16 +7,16 @@ import ( ) func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler, authHandler *AuthHandler) { - router.HandleFunc("GET /sse", sse.ServeHTTP) + router.Handle("GET /sse", authHandler.AuthMiddleware(http.HandlerFunc(sse.ServeHTTP))) fsAssets := http.FileServer(http.Dir("assets")) - router.Handle("GET /assets/", http.StripPrefix("/assets/", fsAssets)) + router.Handle("GET /assets/", authHandler.AuthMiddleware((http.StripPrefix("/assets/", fsAssets)))) icons := http.FileServer(http.Dir("storage/icons")) - router.Handle("GET /icons/", http.StripPrefix("/icons/", icons)) + router.Handle("GET /icons/", authHandler.AuthMiddleware(http.StripPrefix("/icons/", icons))) - router.HandleFunc("GET /login", authHandler.handleAuth) - router.HandleFunc("GET /auch/callback", authHandler.handleCallback) + router.HandleFunc("GET /auth/logout", http.HandlerFunc(authHandler.handleLogout)) + router.HandleFunc("GET /auth/callback", authHandler.handleCallback) router.Handle("GET /", authHandler.AuthMiddleware(http.HandlerFunc(appHandler.appHandler))) } diff --git a/main.go b/main.go index 150a715..f4f45c4 100644 --- a/main.go +++ b/main.go @@ -35,7 +35,7 @@ func main() { lis := fmt.Sprintf(":%d", env.Port) slog.Info("server listening, press ctrl+c to stop", "addr", "http://localhost"+lis) - err = http.ListenAndServe(lis, router) + err = http.ListenAndServe(lis, authHandler.SessionManager.LoadAndSave(router)) if !errors.Is(err, http.ErrServerClosed) { slog.Error("server terminated", "error", err) os.Exit(1) diff --git a/services/claims.services.go b/services/claims.services.go new file mode 100644 index 0000000..81dc7d7 --- /dev/null +++ b/services/claims.services.go @@ -0,0 +1,71 @@ +package services + +import ( + "crypto/sha256" + "encoding/hex" + "net/url" + "strconv" + "strings" +) + +type User struct { + Name string `json:"name"` + Email string `json:"email"` + Gravatar string `json:"gravatar"` +} + +const ( + defaultScheme = "https" + defaultHostname = "www.gravatar.com" +) + +func NewGravatarFromEmail(email string) Gravatar { + hasher := sha256.Sum256([]byte(strings.TrimSpace(email))) + hash := hex.EncodeToString(hasher[:]) + + g := NewGravatar() + g.Hash = hash + return g +} + +func NewGravatar() Gravatar { + return Gravatar{ + Scheme: defaultScheme, + Host: defaultHostname, + } +} + +type Gravatar struct { + Scheme string + Host string + Hash string + Default string + Rating string + Size int +} + +func (g Gravatar) GetURL() string { + path := "/avatar/" + g.Hash + + v := url.Values{} + if g.Size > 0 { + v.Add("s", strconv.Itoa(g.Size)) + } + + if g.Rating != "" { + v.Add("r", g.Rating) + } + + if g.Default != "" { + v.Add("d", g.Default) + } + + url := url.URL{ + Scheme: g.Scheme, + Host: g.Host, + Path: path, + RawQuery: v.Encode(), + } + + return url.String() +} diff --git a/views/home/home.templ b/views/home/home.templ index 8b4cb19..e5dc163 100644 --- a/views/home/home.templ +++ b/views/home/home.templ @@ -2,22 +2,22 @@ package home import ( "fmt" - + "gitlab.unjx.de/flohoss/godash/components" "gitlab.unjx.de/flohoss/godash/services" "gitlab.unjx.de/flohoss/godash/views/layout" - "gitlab.unjx.de/flohoss/godash/components" ) -templ Home(title string, bookmarks *services.Bookmarks, static *services.StaticInformation, live *services.LiveInformation, weather *services.OpenWeather) { +templ Home(title string, user services.User, bookmarks *services.Bookmarks, static *services.StaticInformation, live *services.LiveInformation, weather *services.OpenWeather) {
@components.Weather(weather) + @components.User(user)
- @components.System("icon-[bi--cpu]",static.CPU.Name,"",static.CPU.Threads,"systemCpuPercentage","",live.CPU) - @components.System("icon-[bi--nvme]",live.Disk.Value,fmt.Sprintf(" | %s", static.Disk.Total),static.Disk.Partitions,"systemDiskPercentage","systemDiskValue",live.Disk.Percentage) - @components.System("icon-[bi--memory]",live.Ram.Value,fmt.Sprintf(" | %s", static.Ram.Total),static.Ram.Swap,"systemRamPercentage","systemRamValue",live.Ram.Percentage) - @components.Uptime(static.Host.Architecture,"systemUptimePercentage",live.Uptime) + @components.System("icon-[bi--cpu]", static.CPU.Name, "", static.CPU.Threads, "systemCpuPercentage", "", live.CPU) + @components.System("icon-[bi--nvme]", live.Disk.Value, fmt.Sprintf(" | %s", static.Disk.Total), static.Disk.Partitions, "systemDiskPercentage", "systemDiskValue", live.Disk.Percentage) + @components.System("icon-[bi--memory]", live.Ram.Value, fmt.Sprintf(" | %s", static.Ram.Total), static.Ram.Swap, "systemRamPercentage", "systemRamValue", live.Ram.Percentage) + @components.Uptime(static.Host.Architecture, "systemUptimePercentage", live.Uptime)
for _, a := range bookmarks.Applications {