Commit 3512d652 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Remove CredentialManager singleton

parent ab6d50e9
......@@ -31,22 +31,23 @@ type IgnoringKeyshareHandler struct{}
func (i *IgnoringKeyshareHandler) StartRegistration(m *SchemeManager, callback func(e, p string)) {
}
func parseStorage(t *testing.T) {
func parseStorage(t *testing.T) *CredentialManager {
exists, err := PathExists("testdata/storage/test")
require.NoError(t, err, "pathexists() failed")
if !exists {
require.NoError(t, os.Mkdir("testdata/storage/test", 0755), "Could not create test storage")
}
require.NoError(t, Manager.Init(
manager, err := NewCredentialManager(
"testdata/storage/test",
"testdata/irma_configuration",
&IgnoringKeyshareHandler{},
), "Manager.Init() failed")
)
require.NoError(t, err)
return manager
}
func teardown(t *testing.T) {
MetaStore = newConfigurationStore()
Manager = newCredentialManager()
assert.NoError(t, os.RemoveAll("testdata/storage/test"))
// TODO first RemoveAll?!
}
......@@ -58,17 +59,17 @@ func s2big(s string) (r *big.Int) {
return
}
func parseAndroidStorage(t *testing.T) {
assert.NoError(t, Manager.ParseAndroidStorage(), "ParseAndroidStorage() failed")
func parseAndroidStorage(t *testing.T, manager *CredentialManager) {
assert.NoError(t, manager.ParseAndroidStorage(), "ParseAndroidStorage() failed")
}
func verifyManagerIsUnmarshaled(t *testing.T) {
cred, err := Manager.credential(NewCredentialTypeIdentifier("irma-demo.RU.studentCard"), 0)
func verifyManagerIsUnmarshaled(t *testing.T, manager *CredentialManager) {
cred, err := manager.credential(NewCredentialTypeIdentifier("irma-demo.RU.studentCard"), 0)
assert.NoError(t, err, "could not fetch credential")
assert.NotNil(t, cred, "Credential should exist")
assert.NotNil(t, cred.Attributes[0], "Metadata attribute of irma-demo.RU.studentCard should not be nil")
assert.NotEmpty(t, Manager.CredentialList())
assert.NotEmpty(t, manager.CredentialList())
assert.True(t,
cred.Signature.Verify(cred.PublicKey(), cred.Attributes),
......@@ -93,16 +94,16 @@ func verifyPaillierKey(t *testing.T, PrivateKey *paillierPrivateKey) {
require.Equal(t, plaintext, string(decrypted))
}
func verifyKeyshareIsUnmarshaled(t *testing.T) {
require.NotNil(t, Manager.paillierKeyCache)
require.NotNil(t, Manager.keyshareServers)
func verifyKeyshareIsUnmarshaled(t *testing.T, manager *CredentialManager) {
require.NotNil(t, manager.paillierKeyCache)
require.NotNil(t, manager.keyshareServers)
test := NewSchemeManagerIdentifier("test")
require.Contains(t, Manager.keyshareServers, test)
kss := Manager.keyshareServers[test]
require.Contains(t, manager.keyshareServers, test)
kss := manager.keyshareServers[test]
require.NotEmpty(t, kss.Nonce)
verifyPaillierKey(t, kss.PrivateKey)
verifyPaillierKey(t, Manager.paillierKeyCache)
verifyPaillierKey(t, manager.paillierKeyCache)
}
func verifyStoreIsLoaded(t *testing.T) {
......@@ -134,26 +135,25 @@ func verifyStoreIsLoaded(t *testing.T) {
}
func TestAndroidParse(t *testing.T) {
parseStorage(t)
manager := parseStorage(t)
verifyStoreIsLoaded(t)
parseAndroidStorage(t)
verifyManagerIsUnmarshaled(t)
verifyKeyshareIsUnmarshaled(t)
parseAndroidStorage(t, manager)
verifyManagerIsUnmarshaled(t, manager)
verifyKeyshareIsUnmarshaled(t, manager)
teardown(t)
}
func TestUnmarshaling(t *testing.T) {
parseStorage(t)
parseAndroidStorage(t)
manager := parseStorage(t)
parseAndroidStorage(t, manager)
Manager = newCredentialManager()
err := Manager.Init("testdata/storage/test", "testdata/irma_configuration", nil)
newmanager, err := NewCredentialManager("testdata/storage/test", "testdata/irma_configuration", nil)
require.NoError(t, err)
verifyManagerIsUnmarshaled(t)
verifyKeyshareIsUnmarshaled(t)
verifyManagerIsUnmarshaled(t, newmanager)
verifyKeyshareIsUnmarshaled(t, newmanager)
teardown(t)
}
......@@ -237,14 +237,14 @@ func TestAttributeDisjunctionMarshaling(t *testing.T) {
}
func TestCandidates(t *testing.T) {
parseStorage(t)
parseAndroidStorage(t)
manager := parseStorage(t)
parseAndroidStorage(t, manager)
attrtype := NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
disjunction := &AttributeDisjunction{
Attributes: []AttributeTypeIdentifier{attrtype},
}
attrs := Manager.Candidates(disjunction)
attrs := manager.Candidates(disjunction)
require.NotNil(t, attrs)
require.Len(t, attrs, 1)
......@@ -256,7 +256,7 @@ func TestCandidates(t *testing.T) {
Attributes: []AttributeTypeIdentifier{attrtype},
Values: map[AttributeTypeIdentifier]string{attrtype: "s1234567"},
}
attrs = Manager.Candidates(disjunction)
attrs = manager.Candidates(disjunction)
require.NotNil(t, attrs)
require.Len(t, attrs, 1)
......@@ -264,7 +264,7 @@ func TestCandidates(t *testing.T) {
Attributes: []AttributeTypeIdentifier{attrtype},
Values: map[AttributeTypeIdentifier]string{attrtype: "foobarbaz"},
}
attrs = Manager.Candidates(disjunction)
attrs = manager.Candidates(disjunction)
require.NotNil(t, attrs)
require.Empty(t, attrs)
......@@ -327,14 +327,14 @@ func TestTransport(t *testing.T) {
}
func TestPaillier(t *testing.T) {
parseStorage(t)
parseAndroidStorage(t)
manager := parseStorage(t)
parseAndroidStorage(t, manager)
challenge, _ := gabi.RandomBigInt(256)
comm, _ := gabi.RandomBigInt(1000)
resp, _ := gabi.RandomBigInt(1000)
sk := Manager.paillierKey(true)
sk := manager.paillierKey(true)
bytes, err := sk.Encrypt(challenge.Bytes())
require.NoError(t, err)
cipher := new(big.Int).SetBytes(bytes)
......
......@@ -30,6 +30,7 @@ type keyshareSession struct {
sessionHandler keyshareSessionHandler
pinRequestor KeysharePinRequestor
keyshareServer *keyshareServer
credManager *CredentialManager
}
type keyshareServer struct {
......@@ -127,6 +128,7 @@ func (ks *keyshareServer) HashedPin(pin string) string {
// user cancels; or one of the keyshare servers blocks us.
// Error, blocked or success of the keyshare session is reported back to the keyshareSessionHandler.
func startKeyshareSession(
credManager *CredentialManager,
session IrmaSession,
builders gabi.ProofBuilderList,
sessionHandler keyshareSessionHandler,
......@@ -136,7 +138,7 @@ func startKeyshareSession(
for _, managerID := range session.SchemeManagers() {
if MetaStore.SchemeManagers[managerID].Distributed() {
ksscount++
if _, registered := Manager.keyshareServers[managerID]; !registered {
if _, registered := credManager.keyshareServers[managerID]; !registered {
err := errors.New("Not registered to keyshare server of scheme manager " + managerID.String())
sessionHandler.KeyshareError(err)
return
......@@ -155,6 +157,7 @@ func startKeyshareSession(
sessionHandler: sessionHandler,
transports: map[SchemeManagerIdentifier]*HTTPTransport{},
pinRequestor: pin,
credManager: credManager,
}
askPin := false
......@@ -164,7 +167,7 @@ func startKeyshareSession(
continue
}
ks.keyshareServer = Manager.keyshareServers[managerID]
ks.keyshareServer = ks.credManager.keyshareServers[managerID]
transport := NewHTTPTransport(ks.keyshareServer.URL)
transport.SetHeader(kssUsernameHeader, ks.keyshareServer.Username)
transport.SetHeader(kssAuthHeader, ks.keyshareServer.token)
......@@ -232,7 +235,7 @@ func (ks *keyshareSession) verifyPinAttempt(pin string) (success bool, tries int
continue
}
kss := Manager.keyshareServers[managerID]
kss := ks.credManager.keyshareServers[managerID]
transport := ks.transports[managerID]
pinmsg := keysharePinMessage{Username: kss.Username, Pin: kss.HashedPin(pin)}
pinresult := &keysharePinStatus{}
......
......@@ -12,9 +12,6 @@ import (
"github.com/mhe/gabi"
)
// Manager is the global instance of CredentialManager.
var Manager = newCredentialManager()
// CredentialManager manages credentials.
type CredentialManager struct {
secretkey *big.Int
......@@ -26,13 +23,6 @@ type CredentialManager struct {
paillierKeyCache *paillierPrivateKey
}
func newCredentialManager() *CredentialManager {
return &CredentialManager{
credentials: make(map[CredentialTypeIdentifier]map[int]*credential),
keyshareServers: make(map[SchemeManagerIdentifier]*keyshareServer),
}
}
// CredentialList returns a list of information of all contained credentials.
func (cm *CredentialManager) CredentialList() CredentialList {
list := CredentialList([]*Credential{})
......@@ -87,7 +77,7 @@ func (cm *CredentialManager) credentialByID(id CredentialIdentifier) (cred *cred
// credential returns the requested credential, or nil if we do not have it.
func (cm *CredentialManager) credential(id CredentialTypeIdentifier, counter int) (cred *credential, err error) {
// If the requested credential is not in credential map, we check if its attributes were
// deserialized during Init(). If so, there should be a corresponding signature file,
// deserialized during NewCredentialManager(). If so, there should be a corresponding signature file,
// so we read that, construct the credential, and add it to the credential map
if _, exists := cm.creds(id)[counter]; !exists {
attrs := cm.Attributes(id, counter)
......@@ -373,7 +363,7 @@ func (cm *CredentialManager) KeyshareEnroll(managerID SchemeManagerIdentifier, e
}
transport := NewHTTPTransport(manager.KeyshareServer)
kss, err := newKeyshareServer(Manager.paillierKey(true), manager.KeyshareServer, email)
kss, err := newKeyshareServer(cm.paillierKey(true), manager.KeyshareServer, email)
if err != nil {
return err
}
......
......@@ -35,6 +35,7 @@ type session struct {
ServerURL string
Handler Handler
credManager *CredentialManager
jwt RequestorJwt
irmaSession IrmaSession
transport *HTTPTransport
......@@ -82,7 +83,7 @@ func calcVersion(qr *Qr) (string, error) {
}
// NewSession creates and starts a new IRMA session.
func NewSession(qr *Qr, handler Handler) {
func NewSession(credManager *CredentialManager, qr *Qr, handler Handler) {
version, err := calcVersion(qr)
if err != nil {
handler.Failure(ActionUnknown, &Error{ErrorCode: ErrorProtocolVersionNotSupported, Err: err})
......@@ -90,11 +91,12 @@ func NewSession(qr *Qr, handler Handler) {
}
session := &session{
Version: Version(version),
Action: Action(qr.Type),
ServerURL: qr.URL,
Handler: handler,
transport: NewHTTPTransport(qr.URL),
Version: Version(version),
Action: Action(qr.Type),
ServerURL: qr.URL,
Handler: handler,
transport: NewHTTPTransport(qr.URL),
credManager: credManager,
}
// Check if the action is one of the supported types
......@@ -156,7 +158,7 @@ func (session *session) start() {
}
}
missing := Manager.CheckSatisfiability(session.irmaSession.DisjunctionList())
missing := session.credManager.CheckSatisfiability(session.irmaSession.DisjunctionList())
if len(missing) > 0 {
session.Handler.UnsatisfiableRequest(session.Action, missing)
return
......@@ -193,11 +195,11 @@ func (session *session) do(proceed bool) {
var err error
switch session.Action {
case ActionSigning:
message, err = Manager.Proofs(session.choice, session.irmaSession, true)
message, err = session.credManager.Proofs(session.choice, session.irmaSession, true)
case ActionDisclosing:
message, err = Manager.Proofs(session.choice, session.irmaSession, false)
message, err = session.credManager.Proofs(session.choice, session.irmaSession, false)
case ActionIssuing:
message, err = Manager.IssueCommitments(session.irmaSession.(*IssuanceRequest))
message, err = session.credManager.IssueCommitments(session.irmaSession.(*IssuanceRequest))
}
if err != nil {
session.Handler.Failure(session.Action, &Error{ErrorCode: ErrorCrypto, Err: err})
......@@ -211,15 +213,15 @@ func (session *session) do(proceed bool) {
case ActionSigning:
fallthrough
case ActionDisclosing:
builders, err = Manager.ProofBuilders(session.choice)
builders, err = session.credManager.ProofBuilders(session.choice)
case ActionIssuing:
builders, err = Manager.IssuanceProofBuilders(session.irmaSession.(*IssuanceRequest))
builders, err = session.credManager.IssuanceProofBuilders(session.irmaSession.(*IssuanceRequest))
}
if err != nil {
session.Handler.Failure(session.Action, &Error{ErrorCode: ErrorCrypto, Err: err})
}
startKeyshareSession(session.irmaSession, builders, session, session.Handler)
startKeyshareSession(session.credManager, session.irmaSession, builders, session, session.Handler)
}
}
......@@ -265,7 +267,7 @@ func (session *session) sendResponse(message interface{}) {
session.Handler.Failure(session.Action, err.(*Error))
return
}
if err = Manager.ConstructCredentials(response, session.irmaSession.(*IssuanceRequest)); err != nil {
if err = session.credManager.ConstructCredentials(response, session.irmaSession.(*IssuanceRequest)); err != nil {
session.Handler.Failure(session.Action, &Error{Err: err, ErrorCode: ErrorCrypto})
return
}
......
......@@ -14,8 +14,9 @@ import (
)
type TestHandler struct {
t *testing.T
c chan *Error
t *testing.T
c chan *Error
manager *CredentialManager
}
func (th TestHandler) StatusUpdate(action Action, status Status) {}
......@@ -43,7 +44,7 @@ func (th TestHandler) AskVerificationPermission(request DisclosureRequest, Serve
}
var candidates []*AttributeIdentifier
for _, disjunction := range request.Content {
candidates = Manager.Candidates(disjunction)
candidates = th.manager.Candidates(disjunction)
require.NotNil(th.t, candidates)
require.NotEmpty(th.t, candidates, 1)
choice.Attributes = append(choice.Attributes, candidates[0])
......@@ -132,7 +133,7 @@ func TestSigningSession(t *testing.T) {
name := "testsigclient"
jwtcontents := getSigningJwt(name, id)
sessionHelper(t, jwtcontents, "signature", true)
sessionHelper(t, jwtcontents, "signature", nil)
}
func TestDisclosureSession(t *testing.T) {
......@@ -140,7 +141,7 @@ func TestDisclosureSession(t *testing.T) {
name := "testsp"
jwtcontents := getDisclosureJwt(name, id)
sessionHelper(t, jwtcontents, "verification", true)
sessionHelper(t, jwtcontents, "verification", nil)
}
func TestIssuanceSession(t *testing.T) {
......@@ -148,13 +149,14 @@ func TestIssuanceSession(t *testing.T) {
name := "testip"
jwtcontents := getIssuanceJwt(name, id)
sessionHelper(t, jwtcontents, "issue", true)
sessionHelper(t, jwtcontents, "issue", nil)
}
func sessionHelper(t *testing.T, jwtcontents interface{}, url string, init bool) {
func sessionHelper(t *testing.T, jwtcontents interface{}, url string, manager *CredentialManager) {
init := manager == nil
if init {
parseStorage(t)
parseAndroidStorage(t)
manager = parseStorage(t)
parseAndroidStorage(t, manager)
}
url = "http://localhost:8081/irma_api_server/api/v2/" + url
......@@ -174,7 +176,7 @@ func sessionHelper(t *testing.T, jwtcontents interface{}, url string, init bool)
qr.URL = url + "/" + qr.URL
c := make(chan *Error)
NewSession(qr, TestHandler{t, c})
NewSession(manager, qr, TestHandler{t, c, manager})
if err := <-c; err != nil {
t.Fatal(*err)
......@@ -185,23 +187,25 @@ func sessionHelper(t *testing.T, jwtcontents interface{}, url string, init bool)
}
}
func registerKeyshareServer(t *testing.T) {
parseStorage(t)
parseAndroidStorage(t)
func registerKeyshareServer(t *testing.T) *CredentialManager {
manager := parseStorage(t)
parseAndroidStorage(t, manager)
test := NewSchemeManagerIdentifier("test")
err := Manager.KeyshareRemove(test)
err := manager.KeyshareRemove(test)
require.NoError(t, err)
bytes := make([]byte, 8, 8)
rand.Read(bytes)
email := fmt.Sprintf("%s@example.com", hex.EncodeToString(bytes))
err = Manager.KeyshareEnroll(test, email, "12345")
err = manager.KeyshareEnroll(test, email, "12345")
require.NoError(t, err)
return manager
}
func TestKeyshareSession(t *testing.T) {
registerKeyshareServer(t)
manager := registerKeyshareServer(t)
id := NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
expiry := Timestamp(NewMetadataAttribute().Expiry())
......@@ -215,7 +219,7 @@ func TestKeyshareSession(t *testing.T) {
Attributes: map[string]string{"email": "example@example.com"},
},
)
sessionHelper(t, jwt, "issue", false)
sessionHelper(t, jwt, "issue", manager)
jwt = getDisclosureJwt("testsp", id)
jwt.(*ServiceProviderJwt).Request.Request.Content = append(
......@@ -225,7 +229,7 @@ func TestKeyshareSession(t *testing.T) {
Attributes: []AttributeTypeIdentifier{NewAttributeTypeIdentifier("test.test.mijnirma.email")},
},
)
sessionHelper(t, jwt, "verification", false)
sessionHelper(t, jwt, "verification", manager)
jwt = getSigningJwt("testsigclient", id)
jwt.(*SignatureRequestorJwt).Request.Request.Content = append(
......@@ -235,7 +239,7 @@ func TestKeyshareSession(t *testing.T) {
Attributes: []AttributeTypeIdentifier{NewAttributeTypeIdentifier("test.test.mijnirma.email")},
},
)
sessionHelper(t, jwt, "signature", false)
sessionHelper(t, jwt, "signature", manager)
teardown(t)
}
......@@ -39,49 +39,54 @@ func PathExists(path string) (bool, error) {
return true, err
}
// Init deserializes the credentials from storage.
func (cm *CredentialManager) Init(
// NewCredentialManager deserializes the credentials from storage.
func NewCredentialManager(
storagePath string,
irmaConfigurationPath string,
keyshareHandler KeyshareHandler,
) (err error) {
) (*CredentialManager, error) {
var err error
cm := &CredentialManager{
credentials: make(map[CredentialTypeIdentifier]map[int]*credential),
keyshareServers: make(map[SchemeManagerIdentifier]*keyshareServer),
}
if err = MetaStore.ParseFolder(irmaConfigurationPath); err != nil {
return
return nil, err
}
cm.storagePath = storagePath
if err = cm.ensureStorageExists(); err != nil {
return
return nil, err
}
if cm.secretkey, err = cm.loadSecretKey(); err != nil {
return
return nil, err
}
if cm.attributes, err = cm.loadAttributes(); err != nil {
return
return nil, err
}
if cm.paillierKeyCache, err = cm.loadPaillierKeys(); err != nil {
return
return nil, err
}
if cm.keyshareServers, err = cm.loadKeyshareServers(); err != nil {
return
return nil, err
}
unenrolled := cm.unenrolledKeyshareServers()
switch len(unenrolled) {
case 0:
return
case 0: // nop
case 1:
if keyshareHandler == nil {
return errors.New("Keyshare server found but no KeyshareHandler was given")
return nil, errors.New("Keyshare server found but no KeyshareHandler was given")
}
keyshareHandler.StartRegistration(unenrolled[0], func(email, pin string) {
cm.KeyshareEnroll(unenrolled[0].Identifier(), email, pin)
})
default:
return errors.New("Too many keyshare servers")
return nil, errors.New("Too many keyshare servers")
}
return nil
return cm, nil
}
// ParseAndroidStorage parses an Android cardemu.xml shared preferences file
......
Supports Markdown
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