def addSponsoredIdentity(self, idy: Identity): if idy.role and not Authoriser.isValidRole(idy.role): raise AttributeError("invalid role: {}".format(idy.role)) if idy.identifier in self._sponsored: del self._sponsored[idy.identifier] self._sponsored[idy.identifier] = idy self._sendIdReq(idy)
def __init__(self, identifier: Identifier, trust_anchor: Identifier = None, verkey=None, role=None, last_synced=None, seq_no=None): """ :param identifier: :param trust_anchor: :param verkey: :param role: If role is explicitly passed as `null` then in the request to ledger, `role` key would be sent as None which would stop the Identity's ability to do any privileged actions. If role is not passed, `role` key will not be included in the request to the ledger :param last_synced: :param seq_no: """ self.identity = DidIdentity(identifier, verkey=verkey) self.trustAnchor = trust_anchor # if role and role not in (TRUST_ANCHOR, STEWARD): if not Authoriser.isValidRole(self.correctRole(role)): raise AttributeError("Invalid role {}".format(role)) self._role = role # timestamp for when the ledger was last checked for key replacement or # revocation self.last_synced = last_synced # sequence number of the latest key management transaction for this # identifier self.seqNo = seq_no
def __init__(self, identifier: Identifier, trust_anchor: Identifier=None, verkey=None, role=None, last_synced=None, seq_no=None): """ :param identifier: :param trust_anchor: :param verkey: :param role: If role is explicitly passed as `null` then in the request to ledger, `role` key would be sent as None which would stop the Identity's ability to do any privileged actions. If role is not passed, `role` key will not be included in the request to the ledger :param last_synced: :param seq_no: """ self.identity = DidIdentity(identifier, verkey=verkey) self.trustAnchor = trust_anchor # if role and role not in (TRUST_ANCHOR, STEWARD): if not Authoriser.isValidRole(self.correctRole(role)): raise AttributeError("Invalid role {}".format(role)) self._role = role # timestamp for when the ledger was last checked for key replacement or # revocation self.last_synced = last_synced # sequence number of the latest key management transaction for this # identifier self.seqNo = seq_no
def validate(self, req: Request, config=None): operation = req.operation if operation.get(TXN_TYPE) == POOL_UPGRADE: origin = req.identifier try: originRole = self.idrCache.getRole(origin, isCommitted=False) except: raise UnauthorizedClientRequest( req.identifier, req.reqId, "Nym {} not added to the ledger yet".format(origin)) action = operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present status = self.upgrader.statusInLedger(req.operation.get(NAME), req.operation.get(VERSION)) if status == START and action == START: raise InvalidClientRequest( req.identifier, req.reqId, "Upgrade '{}' is already scheduled".format( req.operation.get(NAME))) r, msg = Authoriser.authorised(POOL_UPGRADE, ACTION, originRole, oldVal=status, newVal=action) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot do {}".format( Roles.nameFromValue(originRole), SovrinTransactions.POOL_UPGRADE.name))
def authErrorWhileUpdatingNode(self, request): origin = request.identifier isTrustee = self.node.secondaryStorage.isTrustee(origin) if not isTrustee: error = super().authErrorWhileUpdatingNode(request) if error: return error origin = request.identifier operation = request.operation nodeNym = operation.get(TARGET_NYM) isSteward = self.node.secondaryStorage.isSteward(origin) actorRole = self.node.graphStore.getRole(origin) _, nodeInfo = self.getNodeInfoFromLedger(nodeNym, excludeLast=False) typ = operation.get(TXN_TYPE) data = deepcopy(operation.get(DATA)) data.pop(ALIAS, None) vals = [] msgs = [] for k in data: oldVal = nodeInfo[DATA][k] newVal = data[k] if oldVal != newVal: r, msg = Authoriser.authorised(typ, k, actorRole, oldVal=oldVal, newVal=newVal, isActorOwnerOfSubject=isSteward) vals.append(r) msgs.append(msg) msg = None if all(vals) else '\n'.join(msgs) return msg
def __init__(self, identifier: Identifier, sponsor: Identifier = None, verkey=None, role=None, last_synced=None, seqNo=None): self.identifier = identifier self.sponsor = sponsor # None indicates the identifier is a cryptonym self.verkey = verkey # None indicates the identifier is a cryptonym # if role and role not in (SPONSOR, STEWARD): if not Authoriser.isValidRole(role): raise AttributeError("Invalid role {}".format(role)) self.role = role # timestamp for when the ledger was last checked for key replacement or # revocation self.last_synced = last_synced # sequence number of the latest key management transaction for this # identifier self.seqNo = seqNo
def _validateNewNym(self, req: Request, op, originRole): role = op.get(ROLE) r, msg = Authoriser.authorised(NYM, ROLE, originRole, oldVal=None, newVal=role) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot add {}".format(Roles.nameFromValue(originRole), Roles.nameFromValue(role)))
def _validateNewNym(self, req: Request, op, originRole): role = op.get(ROLE) r, msg = Authoriser.authorised(NYM, ROLE, originRole, oldVal=None, newVal=role) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot add {}".format( Roles.nameFromValue(originRole), Roles.nameFromValue(role)) )
def _doStaticValidationNym(self, identifier, reqId, operation): role = operation.get(ROLE) nym = operation.get(TARGET_NYM) if not nym: raise InvalidClientRequest( identifier, reqId, "{} needs to be present".format(TARGET_NYM)) if not Authoriser.isValidRole(role): raise InvalidClientRequest(identifier, reqId, "{} not a valid role".format(role)) # TODO: This is not static validation as it involves state s, reason = self.canNymRequestBeProcessed(identifier, operation) if not s: raise InvalidClientRequest(identifier, reqId, reason)
def _doStaticValidationNym(self, identifier, reqId, operation): role = operation.get(ROLE) nym = operation.get(TARGET_NYM) if not nym: raise InvalidClientRequest(identifier, reqId, "{} needs to be present". format(TARGET_NYM)) if not Authoriser.isValidRole(role): raise InvalidClientRequest(identifier, reqId, "{} not a valid role". format(role)) # TODO: This is not static validation as it involves state s, reason = self.canNymRequestBeProcessed(identifier, operation) if not s: raise InvalidClientRequest(identifier, reqId, reason)
def addNymTxnToGraph(self, txn): origin = txn.get(f.IDENTIFIER.nm) role = txn.get(ROLE) if not Authoriser.isValidRole(role): raise ValueError( "Unknown role {} for nym, cannot add nym to graph".format( role)) verkey = txn.get(VERKEY) nym = txn[TARGET_NYM] try: txnId = txn[TXN_ID] seqNo = txn.get(F.seqNo.name) # Since NYM vertex has a unique index on the identifier, # (CID or DID) a unique constraint violation would occur if the # nym exists. Instead of catching an exception, a call to hasNym or # getNym could be done but since NYM update txns would be less # common then NYM adding transactions so avoiding the cost of # extra db query try: self.addNym(txnId, nym, verkey, role, frm=origin, reference=txn.get(REF), seqNo=seqNo) except pyorient.PyOrientORecordDuplicatedException: updateData = {} # Since role can be None, it is only included for update if # it was supplied in the transaction as if ROLE was not # supplied in transaction, the client did not intend to update # the role, but if absence of role is considered None then it # will lead to the identity losing its role if ROLE in txn: updateData[ROLE] = txn[ROLE] if VERKEY in txn: updateData[VERKEY] = txn[VERKEY] self.updateNym(txnId, nym, seqNo, **updateData) else: # Only update edge in case of new NYM transaction self._updateTxnIdEdgeWithTxn(txnId, Edges.AddsNym, txn) except pyorient.PyOrientORecordDuplicatedException: logger.debug("The nym {} was already added to graph".format(nym)) except pyorient.PyOrientCommandException as ex: fault( ex, "An exception was raised while adding " "nym {}: {}".format(nym, ex))
def authErrorWhileUpdatingNode(self, request): origin = request.identifier isTrustee = self.idrCache.hasTrustee(origin, isCommitted=False) if not isTrustee: error = super().authErrorWhileUpdatingNode(request) if error: return error origin = request.identifier operation = request.operation nodeNym = operation.get(TARGET_NYM) data = operation.get(DATA, {}) error = self.dataErrorWhileValidatingUpdate(data, nodeNym) if error: return error isStewardOfNode = self.isStewardOfNode(origin, nodeNym, isCommitted=False) actorRole = self.idrCache.getRole(origin, isCommitted=False) nodeInfo = self.getNodeData(nodeNym, isCommitted=False) data = deepcopy(data) data.pop(ALIAS, None) vals = [] msgs = [] for k in data: oldVal = nodeInfo.get(k, None) if nodeInfo else None newVal = data[k] if k == SERVICES: if not oldVal: oldVal = [] if not newVal: newVal = [] if oldVal != newVal: r, msg = Authoriser.authorised( NODE, k, actorRole, oldVal=oldVal, newVal=newVal, isActorOwnerOfSubject=isStewardOfNode) vals.append(r) msgs.append(msg) msg = None if all(vals) else '\n'.join(msgs) return msg
def validate(self, req: Request, config=None): status = None operation = req.operation typ = operation.get(TXN_TYPE) if typ not in [POOL_UPGRADE, POOL_CONFIG]: return origin = req.identifier try: originRole = self.idrCache.getRole(origin, isCommitted=False) except BaseException: raise UnauthorizedClientRequest( req.identifier, req.reqId, "Nym {} not added to the ledger yet".format(origin)) if typ == POOL_UPGRADE: trname = SovrinTransactions.POOL_UPGRADE.name action = operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present txn = self.upgrader.get_upgrade_txn( lambda txn: txn.get( NAME, None) == req.operation.get( NAME, None) and txn.get(VERSION) == req.operation.get(VERSION), reverse=True) if txn: status = txn.get(ACTION, None) if status == START and action == START: raise InvalidClientRequest( req.identifier, req.reqId, "Upgrade '{}' is already scheduled".format( req.operation.get(NAME))) elif typ == POOL_CONFIG: trname = SovrinTransactions.POOL_CONFIG.name action = None status = None r, msg = Authoriser.authorised( typ, ACTION, originRole, oldVal=status, newVal=action) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot do {}".format( Roles.nameFromValue(originRole), trname))
def _validateExistingNym(self, req: Request, op, originRole, nymData): origin = req.identifier owner = self.idrCache.getOwnerFor(op[TARGET_NYM], isCommitted=False) isOwner = origin == owner updateKeys = [ROLE, VERKEY] for key in updateKeys: if key in op: newVal = op[key] oldVal = nymData.get(key) if oldVal != newVal: r, msg = Authoriser.authorised(NYM, key, originRole, oldVal=oldVal, newVal=newVal, isActorOwnerOfSubject=isOwner) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot update {}".format(Roles.nameFromValue(originRole), key))
def _validateExistingNym(self, req: Request, op, originRole, nymData): origin = req.identifier owner = self.idrCache.getOwnerFor(op[TARGET_NYM], isCommitted=False) isOwner = origin == owner updateKeys = [ROLE, VERKEY] for key in updateKeys: if key in op: newVal = op[key] oldVal = nymData.get(key) if oldVal != newVal: r, msg = Authoriser.authorised( NYM, key, originRole, oldVal=oldVal, newVal=newVal, isActorOwnerOfSubject=isOwner) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot update {}".format( Roles.nameFromValue(originRole), key))
def addNymTxnToGraph(self, txn): origin = txn.get(f.IDENTIFIER.nm) role = txn.get(ROLE) if not Authoriser.isValidRole(role): raise ValueError( "Unknown role {} for nym, cannot add nym to graph".format( role)) nym = txn[TARGET_NYM] verkey = txn.get(VERKEY) try: txnId = txn[TXN_ID] seqNo = txn.get(F.seqNo.name) # Since NYM vertex has a unique index on the identifier, # (CID or DID) a unique constraint violattion would occur if the # nym exists. Instead of catching an exception, a call to hasNym or # getNym could be done but since NYM update txns would be less # common then NYM adding transactions so avoidinhg the cost of # extra db query try: self.addNym(txnId, nym, verkey, role, frm=origin, reference=txn.get(REF), seqNo=seqNo) except pyorient.PyOrientORecordDuplicatedException: self.updateNym(txnId, nym, verkey, seqNo, role) else: # Only update edge in case of new NYM transaction self._updateTxnIdEdgeWithTxn(txnId, Edges.AddsNym, txn) except pyorient.PyOrientORecordDuplicatedException: logger.debug("The nym {} was already added to graph".format(nym)) except pyorient.PyOrientCommandException as ex: fault( ex, "An exception was raised while adding " "nym {}: {}".format(nym, ex))
def checkRequestAuthorized(self, request: Request): op = request.operation typ = op[TXN_TYPE] s = self.graphStore # type: identity_graph.IdentityGraph origin = request.identifier if typ == NYM: try: originRole = s.getRole(origin) except: raise UnauthorizedClientRequest( request.identifier, request.reqId, "Nym {} not added to the ledger yet".format(origin)) role = op.get(ROLE) nym = self.graphStore.getNym(op[TARGET_NYM]) if not nym: # If nym does not exist r, msg = Authoriser.authorised(NYM, ROLE, originRole, oldVal=None, newVal=role) if not r: raise UnauthorizedClientRequest( request.identifier, request.reqId, "{} cannot add {}".format(originRole, role)) else: nym = nym.oRecordData subjectRole = nym.get(ROLE) if subjectRole != role: r, msg = Authoriser.authorised(NYM, ROLE, originRole, oldVal=subjectRole, newVal=role) if not r: raise UnauthorizedClientRequest( request.identifier, request.reqId, "{} cannot update {}".format(originRole, role)) elif typ == ATTRIB: if op.get(TARGET_NYM) and \ op[TARGET_NYM] != request.identifier and \ not s.getSponsorFor(op[TARGET_NYM]) == origin: raise UnauthorizedClientRequest( request.identifier, request.reqId, "Only user's sponsor can add attribute for that user") # TODO: Just for now. Later do something meaningful here elif typ in [ DISCLO, GET_ATTR, CLAIM_DEF, GET_CLAIM_DEF, ISSUER_KEY, GET_ISSUER_KEY ]: pass elif request.operation.get(TXN_TYPE) in POOL_TXN_TYPES: return self.poolManager.checkRequestAuthorized(request) elif typ == POOL_UPGRADE: # TODO: Refactor urgently try: originRole = s.getRole(origin) except: raise UnauthorizedClientRequest( request.identifier, request.reqId, "Nym {} not added to the ledger yet".format(origin)) action = request.operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present status = self.upgrader.statusInLedger( request.operation.get(NAME), request.operation.get(VERSION)) r, msg = Authoriser.authorised(POOL_UPGRADE, ACTION, originRole, oldVal=status, newVal=action) if not r: raise UnauthorizedClientRequest( request.identifier, request.reqId, "{} cannot do {}".format(originRole, POOL_UPGRADE))
def role(self, role): if not Authoriser.isValidRole(self.correctRole(role)): raise AttributeError("Invalid role {}".format(role)) self._role = role
def checkRequestAuthorized(self, request: Request): op = request.operation typ = op[TXN_TYPE] s = self.graphStore # type: identity_graph.IdentityGraph origin = request.identifier if typ == NYM: try: originRole = s.getRole(origin) except: raise UnauthorizedClientRequest( request.identifier, request.reqId, "Nym {} not added to the ledger yet".format(origin)) nymV = self.graphStore.getNym(op[TARGET_NYM]) if not nymV: # If nym does not exist role = op.get(ROLE) r, msg = Authoriser.authorised(NYM, ROLE, originRole, oldVal=None, newVal=role) if not r: raise UnauthorizedClientRequest( request.identifier, request.reqId, "{} cannot add {}".format(originRole, role)) else: nymData = nymV.oRecordData owner = self.graphStore.getOwnerFor(nymData.get(NYM_KEY)) isOwner = origin == owner updateKeys = [ROLE, VERKEY] for key in updateKeys: if key in op: newVal = op[key] oldVal = nymData.get(key) if oldVal != newVal: r, msg = Authoriser.authorised( NYM, key, originRole, oldVal=oldVal, newVal=newVal, isActorOwnerOfSubject=isOwner) if not r: raise UnauthorizedClientRequest( request.identifier, request.reqId, "{} cannot update {}".format( originRole, key)) elif typ == ATTRIB: if op.get(TARGET_NYM) and \ op[TARGET_NYM] != request.identifier and \ not s.getOwnerFor(op[TARGET_NYM]) == origin: raise UnauthorizedClientRequest( request.identifier, request.reqId, "Only identity owner/guardian can add attribute " "for that identity") # TODO: Just for now. Later do something meaningful here elif typ in [ DISCLO, GET_ATTR, SCHEMA, GET_SCHEMA, ISSUER_KEY, GET_ISSUER_KEY ]: pass elif request.operation.get(TXN_TYPE) in POOL_TXN_TYPES: return self.poolManager.checkRequestAuthorized(request) elif typ == POOL_UPGRADE: # TODO: Refactor urgently try: originRole = s.getRole(origin) except: raise UnauthorizedClientRequest( request.identifier, request.reqId, "Nym {} not added to the ledger yet".format(origin)) action = request.operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present status = self.upgrader.statusInLedger( request.operation.get(NAME), request.operation.get(VERSION)) r, msg = Authoriser.authorised(POOL_UPGRADE, ACTION, originRole, oldVal=status, newVal=action) if not r: raise UnauthorizedClientRequest( request.identifier, request.reqId, "{} cannot do {}".format(originRole, POOL_UPGRADE))
def checkValidSovrinOperation(self, identifier, reqId, operation): unknownKeys = set(operation.keys()).difference(set(allOpKeys)) if unknownKeys: raise InvalidClientRequest( identifier, reqId, 'invalid keys "{}"'.format(",".join(unknownKeys))) missingKeys = set(reqOpKeys).difference(set(operation.keys())) if missingKeys: raise InvalidClientRequest( identifier, reqId, 'missing required keys "{}"'.format(",".join(missingKeys))) if operation[TXN_TYPE] not in validTxnTypes: raise InvalidClientRequest( identifier, reqId, 'invalid {}: {}'.format(TXN_TYPE, operation[TXN_TYPE])) if operation[TXN_TYPE] == ATTRIB: dataKeys = {RAW, ENC, HASH}.intersection(set(operation.keys())) if len(dataKeys) != 1: raise InvalidClientRequest( identifier, reqId, '{} should have one and only one of ' '{}, {}, {}'.format(ATTRIB, RAW, ENC, HASH)) if RAW in dataKeys: try: data = json.loads(operation[RAW]) endpoint = data.get(ENDPOINT) check_endpoint_valid(endpoint, required=False) except EndpointException as exc: raise InvalidClientRequest(identifier, reqId, str(exc)) except BaseException as exc: raise InvalidClientRequest(identifier, reqId, str(exc)) # PREVIOUS CODE, ASSUMED ANY EXCEPTION WAS A JSON ISSUE # except: # raise InvalidClientRequest(identifier, reqId, # 'raw attribute {} should be ' # 'JSON'.format(operation[RAW])) if not (not operation.get(TARGET_NYM) or self.graphStore.hasNym(operation[TARGET_NYM])): raise InvalidClientRequest( identifier, reqId, '{} should be added before adding ' 'attribute for it'.format(TARGET_NYM)) if operation[TXN_TYPE] == NYM: role = operation.get(ROLE) nym = operation.get(TARGET_NYM) if not nym: raise InvalidClientRequest( identifier, reqId, "{} needs to be present".format(TARGET_NYM)) if not Authoriser.isValidRole(role): raise InvalidClientRequest(identifier, reqId, "{} not a valid role".format(role)) # Only if not self.canNymRequestBeProcessed(identifier, operation): raise InvalidClientRequest(identifier, reqId, "{} is already present".format(nym)) if operation[TXN_TYPE] == POOL_UPGRADE: action = operation.get(ACTION) if action not in (START, CANCEL): raise InvalidClientRequest( identifier, reqId, "{} not a valid action".format(action)) if action == START: schedule = operation.get(SCHEDULE, {}) isValid, msg = self.upgrader.isScheduleValid( schedule, self.poolManager.nodeIds) if not isValid: raise InvalidClientRequest( identifier, reqId, "{} not a valid schedule since {}".format( schedule, msg))