Commit 8c63cec3 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Make server configurable using flags, env vars, and config file


Co-authored-by: Tomas's avatarConfiks <confiks@scriptbase.org>
parent 4df6271b
...@@ -55,3 +55,7 @@ ...@@ -55,3 +55,7 @@
[prune] [prune]
go-tests = true go-tests = true
unused-packages = true unused-packages = true
[[constraint]]
name = "github.com/spf13/viper"
version = "1.3.1"
...@@ -40,6 +40,7 @@ var IrmaServerConfiguration = &irmaserver.Configuration{ ...@@ -40,6 +40,7 @@ var IrmaServerConfiguration = &irmaserver.Configuration{
IrmaConfigurationPath: filepath.Join(testdata, "irma_configuration"), IrmaConfigurationPath: filepath.Join(testdata, "irma_configuration"),
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"), IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
}, },
DisableRequestorAuthentication: true,
Port: 48682, Port: 48682,
} }
...@@ -50,7 +51,7 @@ var JwtServerConfiguration = &irmaserver.Configuration{ ...@@ -50,7 +51,7 @@ var JwtServerConfiguration = &irmaserver.Configuration{
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"), IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
}, },
Port: 48682, Port: 48682,
AuthenticateRequestors: true, DisableRequestorAuthentication: false,
GlobalPermissions: irmaserver.Permissions{ GlobalPermissions: irmaserver.Permissions{
Disclosing: []string{"*"}, Disclosing: []string{"*"},
Signing: []string{"*"}, Signing: []string{"*"},
......
...@@ -14,13 +14,11 @@ import ( ...@@ -14,13 +14,11 @@ import (
var Logger *logrus.Logger = logrus.StandardLogger() var Logger *logrus.Logger = logrus.StandardLogger()
type Configuration struct { type Configuration struct {
IrmaConfigurationPath string IrmaConfigurationPath string `json:"irmaconf" mapstructure:"irmaconf"`
IssuerPrivateKeysPath string IssuerPrivateKeysPath string `json:"privatekeys" mapstructure:"privatekeys"`
Logger *logrus.Logger `json:"-"`
Logger *logrus.Logger `json:"-"` IssuerPrivateKeys map[irma.IssuerIdentifier]*gabi.PrivateKey `json:"-"`
IrmaConfiguration *irma.Configuration `json:"-"`
IssuerPrivateKeys map[irma.IssuerIdentifier]*gabi.PrivateKey `json:"-"`
IrmaConfiguration *irma.Configuration `json:"-"`
} }
type SessionResult struct { type SessionResult struct {
......
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/privacybydesign/irmago/server" "github.com/privacybydesign/irmago/server"
"github.com/privacybydesign/irmago/server/irmaserver" "github.com/privacybydesign/irmago/server/irmaserver"
"github.com/spf13/cobra"
"github.com/spf13/viper"
) )
var conf *irmaserver.Configuration
func main() { func main() {
var err error var cmd = &cobra.Command{
defer func() { Use: "irmaserver",
if err != nil { Short: "IRMA server for verifying and issuing attributes",
fmt.Println(err.Error()) Run: func(command *cobra.Command, args []string) {
os.Exit(1) if err := configure(); err != nil {
} die(errors.WrapPrefix(err, "Failed to configure server", 0))
os.Exit(0) }
}() if err := irmaserver.Start(conf); err != nil {
die(errors.WrapPrefix(err, "Failed to start server", 0))
}
},
}
if len(os.Args) != 3 { if err := setFlags(cmd); err != nil {
err = errors.New("Usage: irmaserver port path") die(errors.WrapPrefix(err, "Failed to attach flags", 0))
return
} }
port, err := strconv.Atoi(os.Args[1]) if err := cmd.Execute(); err != nil {
if err != nil { die(errors.WrapPrefix(err, "Failed to execute command", 0))
err = errors.New("First argument must be an integer")
return
} }
}
func die(err *errors.Error) {
fmt.Println(err.Error())
fmt.Println()
fmt.Println(string(err.Stack()))
os.Exit(1)
}
func setFlags(cmd *cobra.Command) error {
flags := cmd.Flags()
flags.SortFlags = false
flags.StringP("irmaconf", "i", "./irma_configuration", "path to irma_configuration")
flags.StringP("privatekeys", "k", "", "path to IRMA private keys")
flags.StringP("jwtissuer", "j", "irmaserver", "JWT issuer")
flags.StringP("jwtprivatekey", "w", "", "JWT private key or path to it")
flags.IntP("port", "p", 8088, "Port at which to listen")
flags.Bool("noauth", false, "Whether or not to authenticate requestors")
flags.String("permissions", "", "Default permissions")
flags.String("requestors", "", "Requestor configuration (in JSON)")
return viper.BindPFlags(flags)
}
func configure() error {
fmt.Println("Configuring")
// Environment variables
viper.SetEnvPrefix("IRMASERVER")
viper.AutomaticEnv()
err = irmaserver.Start(&irmaserver.Configuration{ // Configuration file
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/irmaserver/")
viper.AddConfigPath("$HOME/.irmaserver")
if err := viper.ReadInConfig(); err != nil {
fmt.Printf("No configuration file found")
} else {
fmt.Println("Config file: ", viper.ConfigFileUsed())
}
// Read configuration from flags and/or environmental variables
conf = &irmaserver.Configuration{
Configuration: &server.Configuration{ Configuration: &server.Configuration{
IrmaConfigurationPath: os.Args[2], IrmaConfigurationPath: viper.GetString("irmaconf"),
IssuerPrivateKeysPath: viper.GetString("privatekeys"),
Logger: logrus.StandardLogger(),
}, },
Port: port, Port: viper.GetInt("port"),
}) DisableRequestorAuthentication: viper.GetBool("noauth"),
Requestors: make(map[string]irmaserver.Requestor),
GlobalPermissions: irmaserver.Permissions{},
JwtIssuer: viper.GetString("jwtissuer"),
JwtPrivateKey: viper.GetString("jwtprivatekey"),
}
// Handle special permissions
permissions := viper.GetString("permissions")
if len(permissions) > 0 {
if err := json.Unmarshal([]byte(permissions), &conf.GlobalPermissions); err != nil {
return errors.WrapPrefix(err, "Failed to parse permissions", 0)
}
} else if len(viper.GetStringMap("permissions")) > 0 {
if err := viper.UnmarshalKey("permissions", &conf.GlobalPermissions); err != nil {
return errors.WrapPrefix(err, "Failed to unmarshal permissions", 0)
}
}
requestors := viper.GetString("requestors")
if len(requestors) > 0 {
if err := json.Unmarshal([]byte(requestors), &conf.Requestors); err != nil {
return errors.WrapPrefix(err, "Failed to parse requestors", 0)
}
} else if len(viper.GetStringMap("requestors")) > 0 {
if err := viper.UnmarshalKey("requestors", &conf.Requestors); err != nil {
return errors.WrapPrefix(err, "Failed to unmarshal requestors", 0)
}
}
bts, _ := json.MarshalIndent(conf, "", " ")
fmt.Println(string(bts))
fmt.Println("Done configuring")
return nil
} }
...@@ -13,37 +13,42 @@ import ( ...@@ -13,37 +13,42 @@ import (
) )
type Configuration struct { type Configuration struct {
*server.Configuration *server.Configuration `mapstructure:",squash"`
Port int
// Whether or not incoming session requests should be authenticated. If false, anyone // Whether or not incoming session requests should be authenticated. If false, anyone
// can submit session requests. If true, the request is first authenticated against the // can submit session requests. If true, the request is first authenticated against the
// server configuration before the server accepts it. // server configuration before the server accepts it.
AuthenticateRequestors bool DisableRequestorAuthentication bool `json:"noauth" mapstructure:"noauth"`
Requestors map[string]Requestor // Requestor-specific permission and authentication configuration // Port to listen at
GlobalPermissions Permissions // Disclosing, signing or issuance permissions that apply to all requestors Port int `json:"port" mapstructure:"port"`
// Requestor-specific permission and authentication configuration
JwtIssuer string // Used in the "iss" field of result JWTs from /result-jwt and /getproof RequestorsString string `json:"-" mapstructure:"requestors"`
JwtPrivateKey string // Private key to sign result JWTs with. If absent, /result-jwt and /getproof are disabled. Requestors map[string]Requestor `json:"requestors"`
// Disclosing, signing or issuance permissions that apply to all requestors
GlobalPermissionsString string `json:"-" mapstructure:"permissions"`
GlobalPermissions Permissions `json:"permissions"`
// Used in the "iss" field of result JWTs from /result-jwt and /getproof
JwtIssuer string `json:"jwtissuer" mapstructure:"jwtissuer"`
// Private key to sign result JWTs with. If absent, /result-jwt and /getproof are disabled.
JwtPrivateKey string `json:"jwtprivatekey" mapstructure:"jwtprivatekey"`
jwtPrivateKey *rsa.PrivateKey jwtPrivateKey *rsa.PrivateKey
} }
// Permissions specify which attributes or credential a requestor may verify or issue. // Permissions specify which attributes or credential a requestor may verify or issue.
type Permissions struct { type Permissions struct {
Disclosing []string Disclosing []string `json:"disclosing" mapstructure:"disclosing"`
Signing []string Signing []string `json:"signing" mapstructure:"signing"`
Issuing []string Issuing []string `json:"issuing" mapstructure:"issuing"`
} }
// Requestor contains all configuration (disclosure or verification permissions and authentication) // Requestor contains all configuration (disclosure or verification permissions and authentication)
// for a requestor. // for a requestor.
type Requestor struct { type Requestor struct {
Permissions Permissions `mapstructure:",squash"`
AuthenticationMethod AuthenticationMethod AuthenticationMethod AuthenticationMethod `json:"authmethod" mapstructure:"authmethod"`
AuthenticationKey string AuthenticationKey string `json:"key" mapstructure:"key"`
} }
// CanIssue returns whether or not the specified requestor may issue the specified credentials. // CanIssue returns whether or not the specified requestor may issue the specified credentials.
...@@ -109,7 +114,7 @@ func (conf *Configuration) initialize() error { ...@@ -109,7 +114,7 @@ func (conf *Configuration) initialize() error {
return err return err
} }
if !conf.AuthenticateRequestors { if conf.DisableRequestorAuthentication {
conf.Logger.Warn("Authentication of incoming session requests disabled") conf.Logger.Warn("Authentication of incoming session requests disabled")
authenticators = map[AuthenticationMethod]Authenticator{AuthenticationMethodNone: NilAuthenticator{}} authenticators = map[AuthenticationMethod]Authenticator{AuthenticationMethodNone: NilAuthenticator{}}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment