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

Add auto-issuance of keyshare login attribute to keyshare server enrolling

parent f4262fdf
......@@ -668,14 +668,10 @@ func (client *Client) KeyshareEnroll(manager irma.SchemeManagerIdentifier, email
}()
err := client.keyshareEnrollWorker(manager, email, pin)
client.UnenrolledSchemeManagers = client.unenrolledSchemeManagers()
if err != nil {
client.handler.EnrollmentError(manager, err)
} else {
client.handler.EnrollmentSuccess(manager)
}
}()
}
func (client *Client) keyshareEnrollWorker(managerID irma.SchemeManagerIdentifier, email, pin string) error {
......@@ -696,19 +692,30 @@ func (client *Client) keyshareEnrollWorker(managerID irma.SchemeManagerIdentifie
return err
}
message := keyshareEnrollment{
Username: email,
Email: email,
Pin: kss.HashedPin(pin),
PublicKey: (*paillierPublicKey)(&kss.PrivateKey.PublicKey),
}
result := &struct{}{}
err = transport.Post("web/users/selfenroll", result, message)
qr := &irma.Qr{}
err = transport.Post("client/register", qr, message)
if err != nil {
return err
}
// We add the new keyshare server to the client here, without saving it to disk,
// and start the issuance session for the keyshare server login attribute -
// keyshare.go needs the relevant keyshare server to be present in the client.
// If the session succeeds or fails, the keyshare server is stored to disk or
// removed from the client by the keyshareEnrollmentHandler.
client.keyshareServers[managerID] = kss
return client.storage.StoreKeyshareServers(client.keyshareServers)
client.NewSession(qr, &keyshareEnrollmentHandler{
client: client,
pin: pin,
kss: kss,
})
return nil
}
// KeyshareRemove unenrolls the keyshare server of the specified scheme manager.
......
package irmaclient
import (
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago"
)
// keyshareEnrollmentHandler handles the keyshare attribute issuance session
// after registering to a new keyshare server.
type keyshareEnrollmentHandler struct {
pin string
client *Client
kss *keyshareServer
}
// Force keyshareEnrollmentHandler to implement the Handler interface
var _ Handler = (*keyshareEnrollmentHandler)(nil)
// Session handlers in the order they are called
func (h *keyshareEnrollmentHandler) RequestIssuancePermission(request irma.IssuanceRequest, ServerName string, callback PermissionHandler) {
h.kss.Username = request.Credentials[0].Attributes["email"] // TODO magic string
h.client.storage.StoreKeyshareServers(h.client.keyshareServers)
callback(true, nil)
}
func (h *keyshareEnrollmentHandler) RequestPin(remainingAttempts int, callback PinHandler) {
if remainingAttempts == -1 { // -1 signifies that this is the first attempt
callback(true, h.pin)
} else {
h.fail(errors.New("PIN incorrect"))
}
}
func (h *keyshareEnrollmentHandler) Success(action irma.Action, result string) {
_ = h.client.storage.StoreKeyshareServers(h.client.keyshareServers) // TODO handle err?
h.client.UnenrolledSchemeManagers = h.client.unenrolledSchemeManagers()
h.client.handler.EnrollmentSuccess(h.kss.SchemeManagerIdentifier)
}
func (h *keyshareEnrollmentHandler) Failure(action irma.Action, err *irma.SessionError) {
h.fail(err)
}
// fail is a helper to ensure the kss is removed from the client in case of any problem
func (h *keyshareEnrollmentHandler) fail(err error) {
delete(h.client.keyshareServers, h.kss.SchemeManagerIdentifier)
h.client.handler.EnrollmentError(h.kss.SchemeManagerIdentifier, err)
}
// Not interested, ingore
func (h *keyshareEnrollmentHandler) StatusUpdate(action irma.Action, status irma.Status) {}
// The methods below should never be called, so we let each of them fail the session
func (h *keyshareEnrollmentHandler) RequestVerificationPermission(request irma.DisclosureRequest, ServerName string, callback PermissionHandler) {
callback(false, nil)
}
func (h *keyshareEnrollmentHandler) RequestSignaturePermission(request irma.SignatureRequest, ServerName string, callback PermissionHandler) {
callback(false, nil)
}
func (h *keyshareEnrollmentHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) {
callback(false)
}
func (h *keyshareEnrollmentHandler) Cancelled(action irma.Action) {
h.fail(errors.New("Keyshare enrollment session unexpectedly cancelled"))
}
func (h *keyshareEnrollmentHandler) KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int) {
h.fail(errors.New("Keyshare enrollment failed: blocked"))
}
func (h *keyshareEnrollmentHandler) KeyshareEnrollmentIncomplete(manager irma.SchemeManagerIdentifier) {
h.fail(errors.New("Keyshare enrollment failed: registration incomplete"))
}
func (h *keyshareEnrollmentHandler) KeyshareEnrollmentMissing(manager irma.SchemeManagerIdentifier) {
h.fail(errors.New("Keyshare enrollment failed: unenrolled"))
}
func (h *keyshareEnrollmentHandler) UnsatisfiableRequest(action irma.Action, ServerName string, missing irma.AttributeDisjunctionList) {
h.fail(errors.New("Keyshare enrollment failed: unsatisfiable"))
}
......@@ -20,12 +20,26 @@ func TestMain(m *testing.M) {
os.Exit(retCode)
}
type IgnoringClientHandler struct{}
type TestClientHandler struct {
t *testing.T
c chan error
}
func (i *IgnoringClientHandler) UpdateConfiguration(new *irma.IrmaIdentifierSet) {}
func (i *IgnoringClientHandler) UpdateAttributes() {}
func (i *IgnoringClientHandler) EnrollmentError(manager irma.SchemeManagerIdentifier, err error) {}
func (i *IgnoringClientHandler) EnrollmentSuccess(manager irma.SchemeManagerIdentifier) {}
func (i *TestClientHandler) UpdateConfiguration(new *irma.IrmaIdentifierSet) {}
func (i *TestClientHandler) UpdateAttributes() {}
func (i *TestClientHandler) EnrollmentSuccess(manager irma.SchemeManagerIdentifier) {
select {
case i.c <- nil: // nop
default: // nop
}
}
func (i *TestClientHandler) EnrollmentError(manager irma.SchemeManagerIdentifier, err error) {
select {
case i.c <- err: // nop
default:
i.t.Fatal(err)
}
}
func parseStorage(t *testing.T) *Client {
require.NoError(t, fs.CopyDirectory("../testdata/teststorage", "../testdata/storage/test"))
......@@ -33,7 +47,7 @@ func parseStorage(t *testing.T) *Client {
"../testdata/storage/test",
"../testdata/irma_configuration",
"",
&IgnoringClientHandler{},
&TestClientHandler{t: t},
)
require.NoError(t, err)
return manager
......
......@@ -57,6 +57,7 @@ type keyshareEnrollment struct {
Username string `json:"username"`
Pin string `json:"pin"`
PublicKey *paillierPublicKey `json:"publicKey"`
Email string `json:"email"`
}
type keyshareAuthorization struct {
......
......@@ -249,24 +249,7 @@ func sessionHandlerHelper(t *testing.T, jwtcontents interface{}, url string, cli
}
}
func enrollKeyshareServer(t *testing.T, client *Client) {
bytes := make([]byte, 8, 8)
rand.Read(bytes)
email := fmt.Sprintf("%s@example.com", hex.EncodeToString(bytes))
require.NoError(t, client.keyshareEnrollWorker(irma.NewSchemeManagerIdentifier("test"), email, "12345"))
}
// Enroll at a keyshare server and do an issuance, disclosure,
// and issuance session, also using irma-demo credentials deserialized from Android storage
func TestKeyshareEnrollmentAndSessions(t *testing.T) {
client := parseStorage(t)
require.NoError(t, client.RemoveCredentialByHash(
client.Attributes(irma.NewCredentialTypeIdentifier("test.test.mijnirma"), 0).Hash(),
))
require.NoError(t, client.KeyshareRemove(irma.NewSchemeManagerIdentifier("test")))
enrollKeyshareServer(t, client)
func keyshareSessions(t *testing.T, client *Client) {
id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
expiry := irma.Timestamp(irma.NewMetadataAttribute().Expiry())
credid := irma.NewCredentialTypeIdentifier("test.test.mijnirma")
......@@ -300,6 +283,34 @@ func TestKeyshareEnrollmentAndSessions(t *testing.T) {
},
)
sessionHelper(t, jwt, "signature", client)
}
// Enroll at a keyshare server and do an issuance, disclosure,
// and issuance session, also using irma-demo credentials deserialized from Android storage
func TestKeyshareEnrollmentAndSessions(t *testing.T) {
client := parseStorage(t)
credtype := irma.NewCredentialTypeIdentifier("test.test.mijnirma")
// Remove existing registration at test keyshare server
require.NoError(t, client.RemoveCredentialByHash(
client.Attributes(credtype, 0).Hash(),
))
require.NoError(t, client.KeyshareRemove(irma.NewSchemeManagerIdentifier("test")))
// Do a new registration session
c := make(chan error) // channel for TestClientHandler to inform us of result
client.handler.(*TestClientHandler).c = c
bytes := make([]byte, 8, 8)
rand.Read(bytes)
email := fmt.Sprintf("%s@example.com", hex.EncodeToString(bytes))
require.NoError(t, client.keyshareEnrollWorker(irma.NewSchemeManagerIdentifier("test"), email, "12345"))
if err := <-c; err != nil {
t.Fatal(err)
}
require.NotNil(t, client.Attributes(credtype, 0))
keyshareSessions(t, client)
test.ClearTestStorage(t)
}
......@@ -309,40 +320,8 @@ func TestKeyshareEnrollmentAndSessions(t *testing.T) {
// Use keyshareuser.sql to enroll the user at the keyshare server.
func TestKeyshareSessions(t *testing.T) {
client := parseStorage(t)
id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
expiry := irma.Timestamp(irma.NewMetadataAttribute().Expiry())
credid := irma.NewCredentialTypeIdentifier("test.test.mijnirma")
jwt := getCombinedJwt("testip", id)
jwt.(*irma.IdentityProviderJwt).Request.Request.Credentials = append(
jwt.(*irma.IdentityProviderJwt).Request.Request.Credentials,
&irma.CredentialRequest{
Validity: &expiry,
CredentialTypeID: &credid,
Attributes: map[string]string{"email": "example@example.com"},
},
)
sessionHelper(t, jwt, "issue", client)
jwt = getDisclosureJwt("testsp", id)
jwt.(*irma.ServiceProviderJwt).Request.Request.Content = append(
jwt.(*irma.ServiceProviderJwt).Request.Request.Content, //[]*AttributeDisjunction{},
&irma.AttributeDisjunction{
Label: "foo",
Attributes: []irma.AttributeTypeIdentifier{irma.NewAttributeTypeIdentifier("test.test.mijnirma.email")},
},
)
sessionHelper(t, jwt, "verification", client)
jwt = getSigningJwt("testsigclient", id)
jwt.(*irma.SignatureRequestorJwt).Request.Request.Content = append(
jwt.(*irma.SignatureRequestorJwt).Request.Request.Content, //[]*AttributeDisjunction{},
&irma.AttributeDisjunction{
Label: "foo",
Attributes: []irma.AttributeTypeIdentifier{irma.NewAttributeTypeIdentifier("test.test.mijnirma.email")},
},
)
sessionHelper(t, jwt, "signature", client)
keyshareSessions(t, client)
test.ClearTestStorage(t)
}
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