Commit c4860832 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Rename scheme flags and simplify server configuration

parent 93b450d7
......@@ -60,7 +60,7 @@ func EnsureDirectoryExists(path string) error {
if exists {
return nil
}
return os.Mkdir(path, 0700)
return os.MkdirAll(path, 0700)
}
func Empty(path string) bool {
......
......@@ -25,7 +25,7 @@ func StartIrmaClientServer(t *testing.T) {
require.NoError(t, irmarequestor.Initialize(&server.Configuration{
URL: "http://localhost:48680",
Logger: logger,
IrmaConfigurationPath: filepath.Join(testdata, "irma_configuration"),
SchemesPath: filepath.Join(testdata, "irma_configuration"),
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
}))
......
......@@ -38,7 +38,7 @@ var IrmaServerConfiguration = &irmaserver.Configuration{
Configuration: &server.Configuration{
URL: "http://localhost:48682/irma",
Logger: logger,
IrmaConfigurationPath: filepath.Join(testdata, "irma_configuration"),
SchemesPath: filepath.Join(testdata, "irma_configuration"),
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
},
DisableRequestorAuthentication: true,
......@@ -49,7 +49,7 @@ var JwtServerConfiguration = &irmaserver.Configuration{
Configuration: &server.Configuration{
URL: "http://localhost:48682/irma",
Logger: logger,
IrmaConfigurationPath: filepath.Join(testdata, "irma_configuration"),
SchemesPath: filepath.Join(testdata, "irma_configuration"),
IssuerPrivateKeysPath: filepath.Join(testdata, "privatekeys"),
},
Port: 48682,
......
......@@ -9,6 +9,7 @@ import (
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/privacybydesign/irmago/server"
"github.com/spf13/cobra"
)
......@@ -19,7 +20,7 @@ var downloadCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
var path string
var urls []string
defaultIrmaconf := defaultIrmaconfPath()
defaultIrmaconf := server.DefaultSchemesPath()
if len(args) == 0 {
path = defaultIrmaconf
......@@ -99,7 +100,7 @@ func downloadSchemeManager(dest string, urls []string) error {
}
func downloadHelp() string {
defaultIrmaconf := defaultIrmaconfPath()
defaultIrmaconf := server.DefaultSchemesPath()
str := "The download command downloads and saves scheme managers given their URLs, saving it in path (i.e., an irma_configuration folder).\n\n"
if defaultIrmaconf != "" {
str += "If path is not given, the default path " + defaultIrmaconf + " is used.\n"
......
......@@ -11,6 +11,7 @@ import (
"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/privacybydesign/irmago/server"
"github.com/spf13/cobra"
)
......@@ -98,5 +99,5 @@ func prettyprint(ob interface{}) string {
func init() {
RootCmd.AddCommand(metaCmd)
metaCmd.Flags().StringP("irmaconf", "i", defaultIrmaconfPath(), "path to irma_configuration")
metaCmd.Flags().StringP("irmaconf", "i", server.DefaultSchemesPath(), "path to irma_configuration")
}
package cmd
import (
"path/filepath"
"github.com/privacybydesign/irmago/server"
"github.com/spf13/cobra"
)
......@@ -16,11 +13,3 @@ var schemeCmd = &cobra.Command{
func init() {
RootCmd.AddCommand(schemeCmd)
}
func defaultIrmaconfPath() string {
cachepath, err := server.CachePath()
if err != nil {
return ""
}
return filepath.Join(cachepath, "irma_configuration")
}
......@@ -444,7 +444,7 @@ func init() {
flags := sessionCmd.Flags()
flags.SortFlags = false
flags.StringP("irmaconf", "i", defaultIrmaconfPath(), "path to irma_configuration")
flags.StringP("irmaconf", "i", server.DefaultSchemesPath(), "path to irma_configuration")
flags.StringP("privatekeys", "k", "", "path to private keys")
flags.IntP("port", "p", 48680, "port to listen at")
flags.Bool("noqr", false, "Print JSON instead of draw QR")
......
......@@ -7,6 +7,7 @@ import (
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/privacybydesign/irmago/server"
"github.com/spf13/cobra"
)
......@@ -16,12 +17,12 @@ var updateCmd = &cobra.Command{
Long: updateHelp(),
Run: func(cmd *cobra.Command, args []string) {
var paths []string
irmaconf := defaultIrmaconfPath()
irmaconf := server.DefaultSchemesPath()
if len(args) != 0 {
paths = args
} else {
if irmaconf == "" {
die("Failed to read default irma_configuration path", nil)
die("Failed to find default irma_configuration path", nil)
}
files, err := ioutil.ReadDir(irmaconf)
if err != nil {
......@@ -70,7 +71,7 @@ func updateSchemeManager(paths []string) error {
}
func updateHelp() string {
defaultIrmaconf := defaultIrmaconfPath()
defaultIrmaconf := server.DefaultSchemesPath()
str := "The update command updates an IRMA scheme within an irma_configuration folder by comparing its index with the online version, and downloading any new and changed files.\n\n"
if defaultIrmaconf != "" {
str += "If no paths are given, the default schemes at " + defaultIrmaconf + " are updated.\n\n"
......
......@@ -97,12 +97,14 @@ func (sme SchemeManagerError) Error() string {
return fmt.Sprintf("Error parsing scheme manager %s: %s", sme.Manager.Name(), sme.Err.Error())
}
// newConfiguration returns a new configuration. After this
// NewConfiguration returns a new configuration. After this
// ParseFolder() should be called to parse the specified path.
func NewConfiguration(path string) (*Configuration, error) {
return newConfiguration(path, "")
}
// NewConfigurationReadOnly returns a new configuration whose representation on disk
// is never altered. ParseFolder() should be called to parse the specified path.
func NewConfigurationReadOnly(path string) (*Configuration, error) {
conf, err := newConfiguration(path, "")
if err != nil {
......@@ -112,6 +114,8 @@ func NewConfigurationReadOnly(path string) (*Configuration, error) {
return conf, nil
}
// NewConfigurationFromAssets returns a new configuration, copying the schemes out of the assets folder to path.
// ParseFolder() should be called to parse the specified path.
func NewConfigurationFromAssets(path, assets string) (*Configuration, error) {
return newConfiguration(path, assets)
}
......
......@@ -22,14 +22,14 @@ var Logger *logrus.Logger = logrus.StandardLogger()
// Configuration contains configuration for the irmarequestor library and irmaserver.
type Configuration struct {
// irma_configuration. If not given, this will be popupated using IrmaConfigurationPath.
// irma_configuration. If not given, this will be popupated using SchemesPath.
IrmaConfiguration *irma.Configuration `json:"-"`
// Path to schemes to parse (only used if IrmaConfiguration is not given)
IrmaConfigurationPath string `json:"schemes_path" mapstructure:"schemes_path"`
// Path to writable dir to write cache to (only used if IrmaConfiguration is not given)
CachePath string `json:"cache_path" mapstructure:"cache_path"`
// Whether or not to download default IRMA schemes if the specified irma_configuration is empty
DownloadDefaultSchemes bool `json:"download_schemes" mapstructure:"download_schemes"`
// Path to IRMA schemes to parse into IrmaConfiguration (only used if IrmaConfiguration == nil)
SchemesPath string `json:"schemes_path" mapstructure:"schemes_path"`
// If specified, schemes found here are copied into SchemesPath (only used if IrmaConfiguration == nil)
SchemesAssetsPath string `json:"schemes_assets_path" mapstructure:"schemes_assets_path"`
// Whether or not to download default IRMA schemes if the specified schemes path is empty
DownloadDefaultSchemes bool `json:"schemes_download_default" mapstructure:"schemes_download_default"`
// Update all schemes every x minutes (0 to disable)
SchemeUpdateInterval int `json:"schemes_update" mapstructure:"schemes_update"`
// Path to issuer private keys to parse
......@@ -210,17 +210,13 @@ func LocalIP() (string, error) {
return "", errors.New("No IP found")
}
func CachePath() (string, error) {
func DefaultSchemesPath() string {
candidates := make([]string, 0, 2)
if runtime.GOOS != "windows" {
candidates = append(candidates, filepath.Join("/var/tmp", "irma"))
candidates = append(candidates, "/var/tmp/irma/irma_configuration")
}
candidates = append(candidates, filepath.Join(os.TempDir(), "irma"))
path := firstWritablePath(candidates)
if path == "" {
return "", errors.New("No writable temporary directory found")
}
return path, nil
candidates = append(candidates, filepath.Join(os.TempDir(), "irma", "irma_configuration"))
return firstWritablePath(candidates)
}
func firstWritablePath(paths []string) string {
......@@ -255,7 +251,13 @@ func log(level logrus.Level, err error) error {
}
func LogFatal(err error) error {
return log(logrus.FatalLevel, err)
// using log() for this doesn't seem to do anything
if e, ok := err.(*errors.Error); ok && Logger.IsLevelEnabled(logrus.TraceLevel) {
Logger.Fatal(e.ErrorStack())
} else {
Logger.Fatalf("%s %s", reflect.TypeOf(err).String(), err.Error())
}
return err
}
func LogError(err error) error {
......
......@@ -33,13 +33,10 @@ func Initialize(configuration *server.Configuration) error {
if conf.IrmaConfiguration == nil {
var err error
if conf.CachePath == "" {
conf.IrmaConfiguration, err = irma.NewConfiguration(conf.IrmaConfigurationPath)
if conf.SchemesAssetsPath == "" {
conf.IrmaConfiguration, err = irma.NewConfiguration(conf.SchemesPath)
} else {
conf.IrmaConfiguration, err = irma.NewConfigurationFromAssets(
filepath.Join(conf.CachePath, "irma_configuration"),
conf.IrmaConfigurationPath,
)
conf.IrmaConfiguration, err = irma.NewConfigurationFromAssets(conf.SchemesPath, conf.SchemesAssetsPath)
}
if err != nil {
return server.LogError(err)
......@@ -58,7 +55,6 @@ func Initialize(configuration *server.Configuration) error {
return server.LogError(errors.New("no schemes found in irma_configuration folder " + conf.IrmaConfiguration.Path))
}
}
if conf.SchemeUpdateInterval != 0 {
conf.IrmaConfiguration.AutoUpdateSchemes(uint(conf.SchemeUpdateInterval))
}
......
......@@ -49,10 +49,17 @@ Specify -v to see the configuration.`,
if err := configure(command); err != nil {
die(errors.WrapPrefix(err, "Failed to read configuration from file, args, or env vars", 0))
}
conf.SchemeUpdateInterval = 0
interval := conf.SchemeUpdateInterval
download := conf.DownloadDefaultSchemes
conf.SchemeUpdateInterval = 0 // Hack: put this to 0 to prevent Initialize() from immediately updating schemes
conf.DownloadDefaultSchemes = false // and this to false to prevent default scheme downloading
if err := irmaserver.Initialize(conf); err != nil {
die(errors.WrapPrefix(err, "Invalid configuration", 0))
}
conf.SchemeUpdateInterval = interval // restore previous values before printing configuration
conf.DownloadDefaultSchemes = download
bts, _ := json.MarshalIndent(conf, "", " ")
conf.Logger.Debug("Configuration: ", string(bts), "\n")
},
}
......@@ -87,10 +94,7 @@ func setFlags(cmd *cobra.Command) error {
flags := cmd.Flags()
flags.SortFlags = false
cachepath, err := server.CachePath()
if err != nil {
return err
}
schemespath := server.DefaultSchemesPath()
defaulturl, err := server.LocalIP()
if err != nil {
logger.Warn("Could not determine local IP address: ", err.Error())
......@@ -98,33 +102,32 @@ func setFlags(cmd *cobra.Command) error {
defaulturl = "http://" + defaulturl + ":port"
}
flags.StringP("config", "c", "", "Path to configuration file")
flags.StringP("schemes-path", "i", "", "path to irma_configuration")
flags.String("cache-path", cachepath, "Directory for writing cache files to")
flags.Uint("schemes-update", 60, "Update IRMA schemes every x minutes (0 to disable)")
flags.Int("max-request-age", 300, "Max age in seconds of a session request JWT")
flags.StringP("url", "u", defaulturl, "External URL to server to which the IRMA client connects")
flags.StringP("listen-addr", "l", "0.0.0.0", "Address at which to listen")
flags.IntP("port", "p", 8088, "Port at which to listen")
flags.String("client-listen-addr", "", "Address at which server for IRMA app listens")
flags.Int("client-port", 0, "If specified, start a separate server for the IRMA app at his port")
flags.Lookup("listen-addr").Header = `Server address and port to listen on. If the client* configuration options are provided (see also the TLS flags)
flags.StringP("config", "c", "", "path to configuration file")
flags.StringP("schemes-path", "i", schemespath, "path to irma_configuration")
flags.String("schemes-assets-path", "", "if specified, copy schemes from here into schemes-path")
flags.Int("schemes-update", 60, "update IRMA schemes every x minutes (0 to disable)")
flags.Int("max-request-age", 300, "max age in seconds of a session request JWT")
flags.StringP("url", "u", defaulturl, "external URL to server to which the IRMA client connects")
flags.IntP("port", "p", 8088, "port at which to listen")
flags.StringP("listen-addr", "l", "", "address at which to listen (default 0.0.0.0)")
flags.Int("client-port", 0, "if specified, start a separate server for the IRMA app at this port")
flags.String("client-listen-addr", "", "address at which server for IRMA app listens")
flags.Lookup("port").Header = `Server address and port to listen on. If the client* configuration options are provided (see also the TLS flags)
then the endpoints at /session for the requestor and /irma for the irmaclient (i.e. IRMA app) will listen on
distinct network endpoints (e.g., localhost:1234/session and 0.0.0.0:5678/irma).`
flags.Bool("no-auth", false, "Whether or not to authenticate requestors")
flags.String("requestors", "", "Requestor configuration (in JSON)")
flags.Bool("no-auth", false, "whether or not to authenticate requestors")
flags.String("requestors", "", "requestor configuration (in JSON)")
flags.Lookup("no-auth").Header = `Requestor authentication. If disabled, then anyone that can reach this server can submit requests to it.
If it is enabled, then requestor specific configuration must be provided.`
flags.StringSlice("disclose-perms", nil, "list of attributes that all requestors may verify (default *)")
flags.StringSlice("sign-perms", nil, "list of attributes that all requestors may request in signatures (default *)")
flags.StringSlice("issue-perms", nil, "list of attributes that all requestors may issue")
flags.Lookup("disclose-perms").Header = `Default requestor permissions. These apply to all requestors, in addition to any permissions a requestor may
have specifically. May contain wildcards. Separate multiple with comma. Example: irma-demo.*,pbdf.*
By default all requestors may use all attributes in disclosure and signature sessions.
Pass empty string to disable session type.`
flags.Lookup("disclose-perms").Header = `Default requestor permissions. Apply to all requestors, in addition to requestor specific permissions.
May contain wildcards. Separate multiple with comma. Example: irma-demo.*,pbdf.*. By default all requestors
may use all attributes in disclosure and signature sessions. Pass empty string to disable session type.`
flags.StringP("privkeys", "k", "", "path to IRMA private keys")
flags.Lookup("privkeys").Header = `Path to a folder containing IRMA private keys, with filenames scheme.issuer.xml, e.g. irma-demo.MijnOverheid.xml.
......@@ -132,19 +135,19 @@ Private keys may also be stored in the scheme (e.g. irma-demo/MijnOverheid/Priva
flags.StringP("jwt-issuer", "j", "irmaserver", "JWT issuer")
flags.String("jwt-privkey", "", "JWT private key")
flags.String("jwt-privkeyfile", "", "Path to JWT private key")
flags.String("jwt-privkeyfile", "", "path to JWT private key")
flags.Lookup("jwt-issuer").Header = `JWT configuration. Can be omitted but then endpoints that return signed JWTs are disabled.
All of the keys and certificates below are expected in PEM. Pass it either directly, or a path to it
using the corresponding "-file" flag.`
flags.String("tls-cert", "", "TLS certificate")
flags.String("tls-cert-file", "", "Path to TLS certificate ")
flags.String("tls-cert", "", "TLS certificate (chain)")
flags.String("tls-cert-file", "", "path to TLS certificate (chain)")
flags.String("tls-privkey", "", "TLS private key")
flags.String("tls-privkey-file", "", "Path to TLS private key")
flags.String("client-tls-cert", "", "TLS certificate for IRMA app server")
flags.String("client-tls-cert-file", "", "Path to TLS certificate for IRMA app server")
flags.String("tls-privkey-file", "", "path to TLS private key")
flags.String("client-tls-cert", "", "TLS certificate (chain) for IRMA app server")
flags.String("client-tls-cert-file", "", "path to TLS certificate (chain) for IRMA app server")
flags.String("client-tls-privkey", "", "TLS private key for IRMA app server")
flags.String("client-tls-privkey-file", "", "Path to TLS private key for IRMA app server")
flags.String("client-tls-privkey-file", "", "path to TLS private key for IRMA app server")
flags.Lookup("tls-cert").Header = "TLS configuration. Leave empty to disable TLS."
flags.CountP("verbose", "v", "verbose (repeatable)")
......@@ -199,12 +202,13 @@ func configure(cmd *cobra.Command) error {
// Read configuration from flags and/or environmental variables
conf = &irmaserver.Configuration{
Configuration: &server.Configuration{
IrmaConfigurationPath: viper.GetString("schemes-path"),
IssuerPrivateKeysPath: viper.GetString("privkeys"),
CachePath: viper.GetString("cache-path"),
URL: viper.GetString("url"),
SchemeUpdateInterval: viper.GetInt("schemes-update"),
Logger: logger,
DownloadDefaultSchemes: true, // If we get passed an empty schemes-path, download default schemes into it
SchemesPath: viper.GetString("schemes-path"),
SchemesAssetsPath: viper.GetString("schemes-assets-path"),
SchemeUpdateInterval: viper.GetInt("schemes-update"),
IssuerPrivateKeysPath: viper.GetString("privkeys"),
URL: viper.GetString("url"),
Logger: logger,
},
Permissions: irmaserver.Permissions{
Disclosing: handlePermission("disclose-perms"),
......
......@@ -30,6 +30,9 @@ func Start(config *Configuration) error {
return err
}
bts, _ := json.MarshalIndent(conf, "", " ")
conf.Logger.Debug("Configuration: ", string(bts), "\n")
// Start server(s)
if conf.separateClientServer() {
go startClientServer()
......@@ -98,8 +101,6 @@ func Initialize(config *Configuration) error {
if err := conf.initialize(); err != nil {
return err
}
bts, _ := json.MarshalIndent(config, "", " ")
config.Logger.Debug("Configuration: ", string(bts), "\n")
return nil
}
......
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