Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide endpoint with info for sda-cli login #208

Merged
merged 3 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/integration/scripts/charts/dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ C4GHPASSPHRASE="$(random-string)"
export C4GHPASSPHRASE
crypt4gh generate -n c4gh -p "$C4GHPASSPHRASE"
kubectl create secret generic c4gh --from-file="c4gh.sec.pem" --from-file="c4gh.pub.pem" --from-literal=passphrase="${C4GHPASSPHRASE}"

# secret for the OIDC keypair
openssl ecparam -name prime256v1 -genkey -noout -out "jwt.key"
openssl ec -in "jwt.key" -pubout -out "jwt.pub"
Expand Down
2 changes: 1 addition & 1 deletion .github/integration/scripts/charts/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ global:
secretName: c4gh
keyFile: c4gh.sec.pem
publicFile: c4gh.pub.pem
passphrase: PLACEHOLDER_VALUE
passphrase: PLACEHOLDER_VALUE
db:
host: "postgres-sda-db"
user: "postgres"
Expand Down
2 changes: 1 addition & 1 deletion charts/sda-svc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Parameter | Description | Default
`global.cega.password` | Password for the EGA user authentication service. |`""`
`global.c4gh.keyFile` | Private C4GH key. |`c4gh.key`
`global.c4gh.passphrase` | Passphrase for the private C4GH key. |`""`
`global.c4gh.publicFile` | Public key corresponding to the private key, neeeded for tests. |`""`
`global.c4gh.publicFile` | Public key corresponding to the private key, provided in /info endpoint. |`""`
`global.db.host` | Hostname for the database. |`""`
`global.db.name` | Database to connect to. |`lega`
`global.db.passIngest` | Password used for `data in` services. |`""`
Expand Down
15 changes: 15 additions & 0 deletions charts/sda-svc/templates/auth-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ spec:
{{- end }}
- name: RESIGNJWT
value: {{ .Values.global.auth.resignJwt | quote }}
- name: PUBLICFILE
value: "{{ template "c4ghPath" . }}/{{ .Values.global.c4gh.publicFile }}"
{{- if .Values.global.tls.enabled}}
- name: SERVER_CERT
value: {{ template "tlsPath" . }}/tls.crt
Expand Down Expand Up @@ -184,6 +186,10 @@ spec:
- name: jwt
mountPath: {{ template "jwtPath" . }}
{{- end }}
{{- if not .Values.global.vaultSecrets }}
- name: c4gh
mountPath: {{ template "c4ghPath" . }}
jbygdell marked this conversation as resolved.
Show resolved Hide resolved
{{- end }}
volumes:
{{- if and (.Values.global.auth.resignJwt) (not .Values.global.vaultSecrets) }}
- name: jwt
Expand All @@ -196,6 +202,15 @@ spec:
- key: {{ required "The name of the JWT signing key is needed" .Values.global.auth.jwtKey }}
path: {{ .Values.global.auth.jwtKey }}
{{- end }}
{{- if not .Values.global.vaultSecrets }}
- name: c4gh
secret:
defaultMode: 0440
secretName: {{ required "A secret for the C4GH public key is needed" .Values.global.c4gh.secretName }}
items:
- key: {{ required "The C4GH public key is needed" .Values.global.c4gh.publicFile }}
path: {{ .Values.global.c4gh.publicFile }}
{{- end }}
{{- if and (not .Values.global.pkiService) .Values.global.tls.enabled }}
- name: tls
projected:
Expand Down
8 changes: 6 additions & 2 deletions sda-auth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Config struct {
ResignJwt bool
InfoURL string
InfoText string
PublicFile string
}

// NewConfig initializes and parses the config file and/or environment using
Expand Down Expand Up @@ -94,6 +95,7 @@ func (c *Config) readConfig() error {
c.JwtIssuer = viper.GetString("jwtIssuer")
c.InfoURL = viper.GetString("infoUrl")
c.InfoText = viper.GetString("infoText")
c.PublicFile = viper.GetString("publicFile")

viper.SetDefault("ResignJwt", true)
c.ResignJwt = viper.GetBool("resignJwt")
Expand Down Expand Up @@ -172,8 +174,10 @@ func (c *Config) readConfig() error {
log.Printf("Setting log level to '%s'", stringLevel)
}

if viper.GetString("s3Inbox") == "" {
return fmt.Errorf("%s not set", "s3Inbox")
for _, s := range []string{"s3Inbox", "publicFile"} {
if viper.GetString(s) == "" {
return fmt.Errorf("%s not set", s)
}
}

// no need to check the variables for JWT generation if we won't use it
Expand Down
1 change: 1 addition & 0 deletions sda-auth/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ jwtSignatureAlg: "ES256"
resignJwt: true
infoText: "About Federated EGA"
infoUrl: "https://ega-archive.org/about/projects-and-funders/federated-ega/"
publicFile: "/keys/c4gh.pub.pem"
5 changes: 5 additions & 0 deletions sda-auth/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type ConfigTests struct {
ResignJwt bool
InfoURL string
InfoText string
PublicFile string
}

func TestConfigTestSuite(t *testing.T) {
Expand Down Expand Up @@ -89,6 +90,7 @@ func (suite *ConfigTests) SetupTest() {
suite.ResignJwt = true
suite.InfoURL = "https://test.info"
suite.InfoText = "About LEGA"
suite.PublicFile = "public.pem"

// Write config to temp config file
configYaml, err := yaml.Marshal(Config{
Expand All @@ -102,6 +104,7 @@ func (suite *ConfigTests) SetupTest() {
ResignJwt: suite.ResignJwt,
InfoURL: suite.InfoURL,
InfoText: suite.InfoText,
PublicFile: suite.PublicFile,
})
if err != nil {
log.Errorf("Error marshalling config yaml: %v", err)
Expand Down Expand Up @@ -186,6 +189,7 @@ func (suite *ConfigTests) TestConfig() {

os.Setenv("INFOTEXT", fmt.Sprintf("env_%v", suite.InfoText))
os.Setenv("INFOURL", fmt.Sprintf("env_%v", suite.InfoURL))
os.Setenv("PUBLICFILE", fmt.Sprintf("env_%v", suite.PublicFile))

// re-read the config
config, err = NewConfig()
Expand All @@ -212,6 +216,7 @@ func (suite *ConfigTests) TestConfig() {

assert.Equal(suite.T(), fmt.Sprintf("env_%v", suite.InfoText), config.InfoText, "Project info text misread from environment variable")
assert.Equal(suite.T(), fmt.Sprintf("env_%v", suite.InfoURL), config.InfoURL, "Project info text misread from environment variable")
assert.Equal(suite.T(), fmt.Sprintf("env_%v", suite.PublicFile), config.PublicFile, "Public file misread from environment variable")

// Check missing private key
os.Setenv("JWTPRIVATEKEY", "nonexistent-key-file")
Expand Down
14 changes: 14 additions & 0 deletions sda-auth/dev-server/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ services:
- CEGA_USERS_USER=dummy
ports:
- 8443:8443
keygen:
image: golang:alpine3.16
container_name: keygen
command:
- "/bin/sh"
- "-c"
- if [ ! -f "/out/c4gh.sec.pem" ]; then wget -qO- "https://github.com/neicnordic/crypt4gh/releases/latest/download/crypt4gh_linux_x86_64.tar.gz" | tar zxf -;
./crypt4gh generate -n c4gh -p privatekeypass && mv *.pem /out/; fi
volumes:
- /tmp:/out
auth:
container_name: auth
build:
Expand All @@ -55,6 +65,8 @@ services:
condition: service_healthy
cega:
condition: service_started
keygen:
condition: service_completed_successfully
environment:
- ELIXIR_ID=XC56EL11xx
- ELIXIR_PROVIDER=http://oidc:9090
Expand All @@ -73,9 +85,11 @@ services:
- JWTSIGNATUREALG=ES256
- INFOTEXT=About Federated EGA
- INFOURL=https://ega-archive.org/about/projects-and-funders/federated-ega/
- PUBLICFILE=/c4gh.pub.pem
volumes:
- ../keys:/keys
- ../:/sda-auth
- /tmp/c4gh.pub.pem:/c4gh.pub.pem
image: sda-auth
ports:
- 8080:8080
Expand Down
3 changes: 3 additions & 0 deletions sda-auth/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/iris-contrib/middleware/cors v0.0.0-20230311205048-b568fe9b470f
github.com/kataras/iris/v12 v12.2.7
github.com/lestrrat/go-jwx v0.9.1
github.com/neicnordic/crypt4gh v1.7.6
github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282
github.com/sirupsen/logrus v1.9.3
github.com/spf13/viper v1.18.2
Expand All @@ -20,6 +21,7 @@ require (
)

require (
filippo.io/edwards25519 v1.0.0 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
github.com/CloudyKit/jet/v6 v6.2.0 // indirect
Expand All @@ -28,6 +30,7 @@ require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/flosch/pongo2/v4 v4.0.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions sda-auth/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
Expand All @@ -21,6 +23,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
Expand Down Expand Up @@ -96,6 +100,8 @@ github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/neicnordic/crypt4gh v1.7.6 h1:Vqcb8Yb950oaBBJFepDK1oLeu9rZzpywYWVHLmO0oI8=
github.com/neicnordic/crypt4gh v1.7.6/go.mod h1:rqmVXsprDFBRRLJkm1cK9kLETBPGEZmft9lHD/V40wk=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oauth2-proxy/mockoidc v0.0.0-20220308204021-b9169deeb282 h1:TQMyrpijtkFyXpNI3rY5hsZQZw+paiH+BfAlsb81HBY=
Expand Down Expand Up @@ -202,6 +208,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand Down
45 changes: 45 additions & 0 deletions sda-auth/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"os"
"path/filepath"

"github.com/kataras/iris/v12"
"github.com/neicnordic/crypt4gh/keys"
log "github.com/sirupsen/logrus"
)

type Info struct {
ClientID string `json:"client_id"`
OidcURI string `json:"oidc_uri"`
PublicKey string `json:"public_key"`
InboxURI string `json:"inbox_uri"`
}

// Reads the public key file and returns the public key
func readPublicKeyFile(filename string) (key *[32]byte, err error) {
log.Info("Reading Public key file")
file, err := os.Open(filepath.Clean(filename))
if err != nil {
return nil, err
}
defer file.Close()
publicKey, err := keys.ReadPublicKey(file)
if err != nil {
return nil, err
}

return &publicKey, err
}

// getInfo returns information needed by the client to authenticate
func (auth AuthHandler) getInfo(ctx iris.Context) {
info := Info{ClientID: auth.OAuth2Config.ClientID, OidcURI: auth.Config.Elixir.Provider, PublicKey: auth.pubKey, InboxURI: auth.Config.S3Inbox}

pahatz marked this conversation as resolved.
Show resolved Hide resolved
err := ctx.JSON(info)
if err != nil {
log.Error("Failure to get Info ", err)

return
}
}
12 changes: 12 additions & 0 deletions sda-auth/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -35,6 +36,7 @@ type AuthHandler struct {
OIDCProvider *oidc.Provider
htmlDir string
staticDir string
pubKey string
}

func (auth AuthHandler) getInboxConfig(ctx iris.Context, authType string) {
Expand Down Expand Up @@ -380,6 +382,7 @@ func main() {
OIDCProvider: provider,
htmlDir: "./frontend/templates",
staticDir: "./frontend/static",
pubKey: "",
pahatz marked this conversation as resolved.
Show resolved Hide resolved
}

// Initialise web server
Expand Down Expand Up @@ -417,6 +420,15 @@ func main() {
app.Get("/elixir/login", authHandler.getElixirLogin)
app.Get("/elixir/cors_login", authHandler.getElixirCORSLogin)

publicKey, err := readPublicKeyFile(authHandler.Config.PublicFile)
if err != nil {
log.Fatalf("Failed to get public key: %s", err.Error())
}
authHandler.pubKey = hex.EncodeToString(publicKey[:])

// Endpoint for client login info
app.Get("/info", authHandler.getInfo)
pahatz marked this conversation as resolved.
Show resolved Hide resolved

app.UseGlobal(globalHeaders)

if config.Server.Cert != "" && config.Server.Key != "" {
Expand Down
Loading