Commit 12dbf5a9 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Commenting server code

parent 607c65ed
......@@ -14,15 +14,27 @@ import (
// Authenticator instances authenticate incoming session requests. Given details of the HTTP
// post done by the requestor, it is checked whether or not the requestor is known and
// allowed to submit session requests.
type Authenticator interface {
// Initialize is called once on server startup for each requestor that uses this authentication method.
// Used to parse keys or populate caches for later use.
Initialize(name string, requestor Requestor) error
// Authenticate checks, given the HTTP header and POST body, if the authenticator is known
// and allowed to submit session requests. It returns whether or not the current authenticator
// is applicable to this sesion requests; the request itself; the name of the requestor;
// or an error (which is only non-nil if applies is true; i.e. this authenticator applies but
// it was not able to successfully authenticate the request).
headers http.Header, body []byte,
) (applies bool, request irma.SessionRequest, requestor string, err *irma.RemoteError)
Initialize(name string, requestor Requestor) error
type AuthenticationMethod string
// Currently supported requestor authentication methods
const (
AuthenticationMethodPublicKey = "publickey"
AuthenticationMethodPSK = "psk"
......@@ -17,22 +17,28 @@ type Configuration struct {
Port int
// 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
// server configuration before the server accepts it.
AuthenticateRequestors bool
Requestors map[string]Requestor
GlobalPermissions Permissions
Requestors map[string]Requestor // Requestor-specific permission and authentication configuration
GlobalPermissions Permissions // Disclosing, signing or issuance permissions that apply to all requestors
JwtIssuer string
PrivateKey string
JwtIssuer string // Used in the "iss" field of result JWTs from /result-jwt and /getproof
PrivateKey string // Private key to sign result JWTs with. If absent, /result-jwt and /getproof are disabled.
privateKey *rsa.PrivateKey
// Permissions specify which attributes or credential a requestor may verify or issue.
type Permissions struct {
Disclosing []string
Signing []string
Issuing []string
// Requestor contains all configuration (disclosure or verification permissions and authentication)
// for a requestor.
type Requestor struct {
......@@ -40,17 +46,15 @@ type Requestor struct {
AuthenticationKey string
func contains(strings []string, query string) bool {
for _, s := range strings {
if s == query {
return true
return false
// CanIssue returns whether or not the specified requestor may issue the specified credentials.
// (In case of combined issuance/disclosure sessions, this method does not check whether or not
// the identity provider is allowed to verify the attributes being verified; use CanVerifyOrSign
// for that).
func (conf *Configuration) CanIssue(requestor string, creds []*irma.CredentialRequest) (bool, string) {
permissions := append(conf.Requestors[requestor].Issuing, conf.GlobalPermissions.Issuing...)
if len(permissions) == 0 { // requestor is not present in the permissions
return false, ""
for _, cred := range creds {
id := cred.CredentialTypeID
......@@ -67,6 +71,8 @@ func (conf *Configuration) CanIssue(requestor string, creds []*irma.CredentialRe
return true, ""
// CanVerifyOrSign returns whether or not the specified requestor may use the selected attributes
// in any of the supported session types.
func (conf *Configuration) CanVerifyOrSign(requestor string, action irma.Action, disjunctions irma.AttributeDisjunctionList) (bool, string) {
var permissions []string
switch action {
......@@ -104,7 +110,7 @@ func (conf *Configuration) initialize() error {
if !conf.AuthenticateRequestors {
conf.Logger.Warn("Requestor authentication disabled")
conf.Logger.Warn("Authentication of incoming session requests disabled")
authenticators = map[AuthenticationMethod]Authenticator{AuthenticationMethodNone: NilAuthenticator{}}
// Leaving the global permission whitelists empty in this mode means enabling it for everyone
......@@ -120,7 +126,6 @@ func (conf *Configuration) initialize() error {
conf.Logger.Info("No issuance whitelist found: allowing issuance of any credential (for which private keys are installed)")
conf.GlobalPermissions.Issuing = []string{"*"}
return nil
......@@ -129,6 +134,7 @@ func (conf *Configuration) initialize() error {
AuthenticationMethodPSK: &PresharedKeyAuthenticator{presharedkeys: map[string]string{}},
// Initialize authenticators
for name, requestor := range conf.Requestors {
authenticator, ok := authenticators[requestor.AuthenticationMethod]
if !ok {
......@@ -163,3 +169,13 @@ func (conf *Configuration) readPrivateKey() error {
conf.privateKey, err = jwt.ParseRSAPrivateKeyFromPEM(keybytes)
return err
// Return true iff query equals an element of strings.
func contains(strings []string, query string) bool {
for _, s := range strings {
if s == query {
return true
return false
......@@ -39,6 +39,8 @@ func Stop() {
// Handler returns a http.Handler that handles all IRMA requestor messages
// and IRMA client messages.
func Handler(config *Configuration) (http.Handler, error) {
conf = config
if err := irmarequestor.Initialize(conf.Configuration); err != nil {
......@@ -57,8 +59,10 @@ func Handler(config *Configuration) (http.Handler, error) {
router.Post("/create", handleCreate)
router.Get("/status/{token}", handleStatus)
router.Get("/result/{token}", handleResult)
// Routes for getting signed JWTs containing the session result. Only work if configuration has a private key
router.Get("/result-jwt/{token}", handleJwtResult)
router.Get("/getproof/{token}", handleJwtProofs)
router.Get("/getproof/{token}", handleJwtProofs) // irma_api_server-compatible JWT
return router, nil
......@@ -70,7 +74,9 @@ func handleCreate(w http.ResponseWriter, r *http.Request) {
// Authenticate request: check if the requestor is known and allowed to submit requests
// Authenticate request: check if the requestor is known and allowed to submit requests.
// We do this by feeding the HTTP POST details to all known authenticators, and see if
// one of them is applicable and able to authenticate the request.
var (
request irma.SessionRequest
requestor string
......@@ -94,7 +100,6 @@ func handleCreate(w http.ResponseWriter, r *http.Request) {
// Authorize request: check if the requestor is allowed to verify or issue
// the requested attributes or credentials
disjunctions := request.ToDisclose()
if request.Action() == irma.ActionIssuing {
allowed, reason := conf.CanIssue(requestor, request.(*irma.IssuanceRequest).Credentials)
if !allowed {
......@@ -102,6 +107,7 @@ func handleCreate(w http.ResponseWriter, r *http.Request) {
disjunctions := request.ToDisclose()
if len(disjunctions) > 0 {
allowed, reason := conf.CanVerifyOrSign(requestor, request.Action(), disjunctions)
if !allowed {
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