conf.go 4.53 KB
Newer Older
1
2
3
4
5
6
7
8
package irmaserver

import (
	"crypto/rsa"
	"io/ioutil"
	"strings"

	"github.com/dgrijalva/jwt-go"
9
	"github.com/go-errors/errors"
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
	"github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/internal/fs"
	"github.com/privacybydesign/irmago/server"
)

type Configuration struct {
	*server.Configuration

	Port int

	AuthenticateRequestors bool
	Requestors             map[string]Requestor
	GlobalPermissions      Permissions

	JwtIssuer  string
	PrivateKey string

	privateKey *rsa.PrivateKey
}

type Permissions struct {
	Disclosing []string
	Signing    []string
	Issuing    []string
}

type Requestor struct {
	Permissions

	AuthenticationMethod AuthenticationMethod
	AuthenticationKey    string
}

func contains(strings []string, query string) bool {
	for _, s := range strings {
		if s == query {
			return true
		}
	}
	return false
}

func (conf *Configuration) CanIssue(requestor string, creds []*irma.CredentialRequest) (bool, string) {
	permissions := append(conf.Requestors[requestor].Issuing, conf.GlobalPermissions.Issuing...)

	for _, cred := range creds {
		id := cred.CredentialTypeID
		if contains(permissions, "*") ||
			contains(permissions, id.Root()+".*") ||
			contains(permissions, id.IssuerIdentifier().String()+".*") ||
			contains(permissions, id.String()) {
			continue
		} else {
			return false, id.String()
		}
	}

	return true, ""
}

func (conf *Configuration) CanVerifyOrSign(requestor string, action irma.Action, disjunctions irma.AttributeDisjunctionList) (bool, string) {
	var permissions []string
	switch action {
	case irma.ActionDisclosing:
		permissions = append(conf.Requestors[requestor].Disclosing, conf.GlobalPermissions.Disclosing...)
	case irma.ActionIssuing:
		permissions = append(conf.Requestors[requestor].Disclosing, conf.GlobalPermissions.Disclosing...)
	case irma.ActionSigning:
		permissions = append(conf.Requestors[requestor].Signing, conf.GlobalPermissions.Signing...)
	}
	if len(permissions) == 0 { // requestor is not present in the permissions
		return false, ""
	}

	for _, disjunction := range disjunctions {
		for _, attr := range disjunction.Attributes {
			if contains(permissions, "*") ||
				contains(permissions, attr.Root()+".*") ||
				contains(permissions, attr.CredentialTypeIdentifier().IssuerIdentifier().String()+".*") ||
				contains(permissions, attr.CredentialTypeIdentifier().String()+".*") ||
				contains(permissions, attr.String()) {
				continue
			} else {
				return false, attr.String()
			}
		}
	}

	return true, ""
}

func (conf *Configuration) initialize() error {
	if err := conf.readPrivateKey(); err != nil {
		return err
	}

	if !conf.AuthenticateRequestors {
		conf.Logger.Warn("Requestor authentication disabled")
108
		authenticators = map[AuthenticationMethod]Authenticator{AuthenticationMethodNone: NilAuthenticator{}}
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

		// Leaving the global permission whitelists empty in this mode means enabling it for everyone
		if len(conf.GlobalPermissions.Disclosing) == 0 {
			conf.Logger.Info("No disclosing whitelist found: allowing verification of any attribute")
			conf.GlobalPermissions.Disclosing = []string{"*"}
		}
		if len(conf.GlobalPermissions.Signing) == 0 {
			conf.Logger.Info("No signing whitelist found: allowing attribute-based signature sessions with any attribute")
			conf.GlobalPermissions.Signing = []string{"*"}
		}
		if len(conf.GlobalPermissions.Issuing) == 0 {
			conf.Logger.Info("No issuance whitelist found: allowing issuance of any credential (for which private keys are installed)")
			conf.GlobalPermissions.Issuing = []string{"*"}
		}

		return nil
	}

127
128
129
	authenticators = map[AuthenticationMethod]Authenticator{
		AuthenticationMethodPublicKey: &PublicKeyAuthenticator{publickeys: map[string]*rsa.PublicKey{}},
		AuthenticationMethodPSK:       &PresharedKeyAuthenticator{presharedkeys: map[string]string{}},
130
131
	}

132
133
134
135
136
137
	for name, requestor := range conf.Requestors {
		authenticator, ok := authenticators[requestor.AuthenticationMethod]
		if !ok {
			return errors.Errorf("Requestor %s has unsupported authentication type")
		}
		if err := authenticator.Initialize(name, requestor); err != nil {
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
			return err
		}
	}

	return nil
}

func (conf *Configuration) readPrivateKey() error {
	if conf.PrivateKey == "" {
		return nil
	}

	var keybytes []byte
	var err error
	if strings.HasPrefix(conf.PrivateKey, "-----BEGIN") {
		keybytes = []byte(conf.PrivateKey)
	} else {
		if err = fs.AssertPathExists(conf.PrivateKey); err != nil {
			return err
		}
		if keybytes, err = ioutil.ReadFile(conf.PrivateKey); err != nil {
			return err
		}
	}

	conf.privateKey, err = jwt.ParseRSAPrivateKeyFromPEM(keybytes)
	return err
}