add backend support for Apple auth provider

It's a bit different from other OAuth providers and requires a
different set of options and a private key file.
This commit is contained in:
Dmitry Verkhoturov
2023-01-03 23:47:42 -06:00
committed by Umputun
parent d7e9be99f9
commit c1b3fba344
10 changed files with 77 additions and 18 deletions
+34 -10
View File
@@ -96,16 +96,17 @@ type ServerCommand struct {
SendJWTHeader bool `long:"send-jwt-header" env:"SEND_JWT_HEADER" description:"send JWT as a header instead of cookie"`
SameSite string `long:"same-site" env:"SAME_SITE" description:"set same site policy for cookies" choice:"default" choice:"none" choice:"lax" choice:"strict" default:"default"` // nolint
Google AuthGroup `group:"google" namespace:"google" env-namespace:"GOOGLE" description:"Google OAuth"`
Github AuthGroup `group:"github" namespace:"github" env-namespace:"GITHUB" description:"Github OAuth"`
Facebook AuthGroup `group:"facebook" namespace:"facebook" env-namespace:"FACEBOOK" description:"Facebook OAuth"`
Microsoft AuthGroup `group:"microsoft" namespace:"microsoft" env-namespace:"MICROSOFT" description:"Microsoft OAuth"`
Yandex AuthGroup `group:"yandex" namespace:"yandex" env-namespace:"YANDEX" description:"Yandex OAuth"`
Twitter AuthGroup `group:"twitter" namespace:"twitter" env-namespace:"TWITTER" description:"Twitter OAuth"`
Patreon AuthGroup `group:"patreon" namespace:"patreon" env-namespace:"PATREON" description:"Patreon OAuth"`
Telegram bool `long:"telegram" env:"TELEGRAM" description:"Enable Telegram auth (using token from telegram.token)"`
Dev bool `long:"dev" env:"DEV" description:"enable dev (local) oauth2"`
Anonymous bool `long:"anon" env:"ANON" description:"enable anonymous login"`
Apple AppleGroup `group:"apple" namespace:"apple" env-namespace:"APPLE" description:"Apple OAuth"`
Google AuthGroup `group:"google" namespace:"google" env-namespace:"GOOGLE" description:"Google OAuth"`
Github AuthGroup `group:"github" namespace:"github" env-namespace:"GITHUB" description:"Github OAuth"`
Facebook AuthGroup `group:"facebook" namespace:"facebook" env-namespace:"FACEBOOK" description:"Facebook OAuth"`
Microsoft AuthGroup `group:"microsoft" namespace:"microsoft" env-namespace:"MICROSOFT" description:"Microsoft OAuth"`
Yandex AuthGroup `group:"yandex" namespace:"yandex" env-namespace:"YANDEX" description:"Yandex OAuth"`
Twitter AuthGroup `group:"twitter" namespace:"twitter" env-namespace:"TWITTER" description:"Twitter OAuth"`
Patreon AuthGroup `group:"patreon" namespace:"patreon" env-namespace:"PATREON" description:"Patreon OAuth"`
Telegram bool `long:"telegram" env:"TELEGRAM" description:"Enable Telegram auth (using token from telegram.token)"`
Dev bool `long:"dev" env:"DEV" description:"enable dev (local) oauth2"`
Anonymous bool `long:"anon" env:"ANON" description:"enable anonymous login"`
Email struct {
Enable bool `long:"enable" env:"ENABLE" description:"enable auth via email"`
From string `long:"from" env:"FROM" description:"from email address"`
@@ -133,6 +134,14 @@ type ImageProxyGroup struct {
CacheExternal bool `long:"cache-external" env:"CACHE_EXTERNAL" description:"enable caching for external images"`
}
// AppleGroup defines options for Apple auth params
type AppleGroup struct {
CID string `long:"cid" env:"CID" description:"Apple client ID"`
TID string `long:"tid" env:"TID" description:"Apple service ID"`
KID string `long:"kid" env:"KID" description:"Private key ID"`
PrivateKeyFilePath string `long:"private-key-filepath" env:"PRIVATE_KEY_FILEPATH" description:"Private key file location" default:"/var/apple.p8"`
}
// AuthGroup defines options group for auth params
type AuthGroup struct {
CID string `long:"cid" env:"CID" description:"OAuth client ID"`
@@ -829,12 +838,27 @@ func (s *ServerCommand) makeCache() (LoadingCache, error) {
return nil, fmt.Errorf("unsupported cache type %s", s.Cache.Type)
}
//nolint:gocyclo // simple code but many if checks
func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) error {
providersCount := 0
if s.Auth.Telegram {
providersCount++
}
if s.Auth.Apple.CID != "" && s.Auth.Apple.TID != "" && s.Auth.Apple.KID != "" {
err := authenticator.AddAppleProvider(
provider.AppleConfig{
ClientID: s.Auth.Apple.CID,
TeamID: s.Auth.Apple.TID,
KeyID: s.Auth.Apple.KID,
},
provider.LoadApplePrivateKeyFromFile(s.Auth.Apple.PrivateKeyFilePath),
)
if err != nil {
return err
}
providersCount++
}
if s.Auth.Google.CID != "" && s.Auth.Google.CSEC != "" {
authenticator.AddProvider("google", s.Auth.Google.CID, s.Auth.Google.CSEC)
providersCount++
+4 -2
View File
@@ -79,7 +79,7 @@ func TestServerApp_DevMode(t *testing.T) {
waitForHTTPServerStart(port)
providers := app.restSrv.Authenticator.Providers()
require.Equal(t, 9+1, len(providers), "extra auth provider")
require.Equal(t, 10+1, len(providers), "extra auth provider")
assert.Equal(t, "dev", providers[len(providers)-2].Name(), "dev auth provider")
// send ping
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/api/v1/ping", port))
@@ -107,7 +107,7 @@ func TestServerApp_AnonMode(t *testing.T) {
waitForHTTPServerStart(port)
providers := app.restSrv.Authenticator.Providers()
require.Equal(t, 9+1, len(providers), "extra auth provider for anon")
require.Equal(t, 10+1, len(providers), "extra auth provider for anon")
assert.Equal(t, "anonymous", providers[len(providers)-1].Name(), "anon auth provider")
client := http.Client{Timeout: 10 * time.Second}
@@ -758,6 +758,8 @@ func prepServerApp(t *testing.T, fn func(o ServerCommand) ServerCommand) (*serve
cmd.Avatar.FS.Path, cmd.Avatar.Type, cmd.BackupLocation, cmd.Image.FS.Path = "/tmp/remark42_test", "fs", "/tmp/remark42_test", "/tmp/remark42_test"
cmd.Store.Bolt.Path = fmt.Sprintf("/tmp/%d", cmd.Port)
cmd.Store.Bolt.Timeout = 10 * time.Second
cmd.Auth.Apple.CID, cmd.Auth.Apple.KID, cmd.Auth.Apple.TID = "cid", "kid", "tid"
cmd.Auth.Apple.PrivateKeyFilePath = "testdata/apple.p8"
cmd.Auth.Github.CSEC, cmd.Auth.Github.CID = "csec", "cid"
cmd.Auth.Google.CSEC, cmd.Auth.Google.CID = "csec", "cid"
cmd.Auth.Facebook.CSEC, cmd.Auth.Facebook.CID = "csec", "cid"
+6
View File
@@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgGH2MylyZjjRdauTk
xxXW6p8VSHqIeVRRKSJPg1xn6+KgCgYIKoZIzj0DAQehRANCAAS/mNzQ7aBbIBr3
DiHiJGIDEzi6+q3mmyhH6ZWQWFdFei2qgdyM1V6qtRPVq+yHBNSBebbR4noE/IYO
hMdWYrKn
-----END PRIVATE KEY-----
+1 -1
View File
@@ -11,7 +11,7 @@ require (
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.2
github.com/go-pkgz/auth v1.20.1-0.20221226231300-65f433fba0f1
github.com/go-pkgz/auth v1.20.1-0.20230103203948-168bd5a101b7
github.com/go-pkgz/jrpc v0.3.0
github.com/go-pkgz/lcw v1.0.3-0.20221226231215-a66ea7c4aff7
github.com/go-pkgz/lgr v0.10.4
+2
View File
@@ -142,6 +142,8 @@ github.com/go-oauth2/oauth2/v4 v4.5.1 h1:3vxp+cjLqDe1TbogbwtMyeHRHr1tD+ksrK7xNpp
github.com/go-oauth2/oauth2/v4 v4.5.1/go.mod h1:wk/2uLImWIa9VVQDgxz99H2GDbhmfi/9/Xr+GvkSUSQ=
github.com/go-pkgz/auth v1.20.1-0.20221226231300-65f433fba0f1 h1:MJA4rZAwjd+KpaR2PqrxeDPloNu9Wml1UVQjL2fOtVM=
github.com/go-pkgz/auth v1.20.1-0.20221226231300-65f433fba0f1/go.mod h1:fG1CP4+LDPnebYeO1BAZg/euTQQ8cnGn+5ZrXvJfckA=
github.com/go-pkgz/auth v1.20.1-0.20230103203948-168bd5a101b7 h1:ktKI3Y3UytkBLL1cOEzJmAi3nNKeaRGOzDj51Kgqp6M=
github.com/go-pkgz/auth v1.20.1-0.20230103203948-168bd5a101b7/go.mod h1:fG1CP4+LDPnebYeO1BAZg/euTQQ8cnGn+5ZrXvJfckA=
github.com/go-pkgz/email v0.3.1-0.20221002173339-19d25a20d99c/go.mod h1:TpnmSLkQW3FyICit2hn7WIhCUDrhCX6btzz5wS3wHRI=
github.com/go-pkgz/email v0.4.1 h1:2vtP2gibsSzqhz6eD5DklSp11m657XEVf17fuXaxMvk=
github.com/go-pkgz/email v0.4.1/go.mod h1:BdxglsQnymzhfdbnncEE72a6DrucZHy6I+42LK2jLEc=
+5 -1
View File
@@ -208,7 +208,11 @@ func (ah *AppleHandler) initPrivateKey() error {
if err != nil {
return err
}
ah.conf.publicKey = ah.conf.privateKey.(*ecdsa.PrivateKey).Public()
publicKey, ok := ah.conf.privateKey.(*ecdsa.PrivateKey)
if !ok {
return fmt.Errorf("provided private key is not ECDSA")
}
ah.conf.publicKey = publicKey.Public()
ah.conf.clientSecret, err = ah.createClientSecret()
if err != nil {
return err
+1 -1
View File
@@ -65,7 +65,7 @@ github.com/go-chi/render
github.com/go-oauth2/oauth2/v4
github.com/go-oauth2/oauth2/v4/errors
github.com/go-oauth2/oauth2/v4/server
# github.com/go-pkgz/auth v1.20.1-0.20221226231300-65f433fba0f1
# github.com/go-pkgz/auth v1.20.1-0.20230103203948-168bd5a101b7
## explicit; go 1.17
github.com/go-pkgz/auth
github.com/go-pkgz/auth/avatar