Skip to content

Commit 0a7767d

Browse files
authored
Merge pull request #405 from wultra/issues/backport-revoke-recovery
Backport of revoking of recovery codes during remove activation action
2 parents 66d8e2b + eaba150 commit 0a7767d

File tree

12 files changed

+81
-17
lines changed

12 files changed

+81
-17
lines changed

docs/PowerAuth-Server-0.22.0.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,7 @@ The [VerifyOfflineSignature](./SOAP-Service-Methods.md#method-verifyofflinesigna
313313
### External User Identifier
314314

315315
The [CommitActivation](./SOAP-Service-Methods.md#method-commitactivation), [RemoveActivation](./SOAP-Service-Methods.md#method-removeactivation), [BlockActivation](./SOAP-Service-Methods.md#method-blockactivation) and [UnblockActivation](./SOAP-Service-Methods.md#method-unblockactivation) methods have been updated to allow specification of external user identifier. The related PowerAuth client methods have been updated to reflect the change of parameters. If you use any of these methods, please update the SOAP method call.
316+
317+
### Revoking Recovery Codes on Activation Removal
318+
319+
We added an optional `revokeRecoveryCodes` attribute to [activation removal service call](./SOAP-Service-Methods.md#method-removeactivation). This flag indicates if recovery codes that are associated with removed activation should be also revoked. By default, the value of the flag is `false`, hence omitting the flag results in the same behavior as before this change.

docs/PowerAuth-Server-0.23.0.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,10 @@ The reason for the change is that the original function is no longer usable for
9696

9797
## Database record encryption
9898

99-
If you turned on additional database record encryption in any previous PowerAuth Server version (see [Encrypting Records in Database](Encrypting-Records-in-Database.md#additional-record-encryption)), please contact us at [[email protected]](mailto:[email protected]). The encryption scheme has been slightly changed, so we can help you with the migration.
99+
If you turned on additional database record encryption in any previous PowerAuth Server version (see [Encrypting Records in Database](Encrypting-Records-in-Database.md#additional-record-encryption)), please contact us at [[email protected]](mailto:[email protected]). The encryption scheme has been slightly changed, so we can help you with the migration.
100+
101+
## SOAP Endpoint Changes
102+
103+
### Revoking Recovery Codes on Activation Removal
104+
105+
We added an optional `revokeRecoveryCodes` attribute to [activation removal service call](./SOAP-Service-Methods.md#method-removeactivation). This flag indicates if recovery codes that are associated with removed activation should be also revoked. By default, the value of the flag is `false`, hence omitting the flag results in the same behavior as before this change.

docs/SOAP-Service-Methods.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ Remove activation with given ID. This operation is irreversible. Activations can
491491
|------|------|-------------|
492492
| `String` | `activationId` | An identifier of an activation |
493493
| `String` | `externalUserId` | User ID of user who removed the activation. Use null value if activation owner caused the change. |
494+
| `Boolean` | `revokeRecoveryCodes` | An optional flag that indicates if recovery codes, that were created in the scope of the removed activation, should be also revoked. |
494495

495496
#### Response
496497

powerauth-java-client-axis/src/main/java/io/getlime/security/powerauth/soap/axis/client/PowerAuthServiceClient.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,22 @@ public PowerAuthPortV3ServiceStub.RemoveActivationResponse removeActivation(Powe
476476
* @throws RemoteException In case of a business logic error.
477477
*/
478478
public PowerAuthPortV3ServiceStub.RemoveActivationResponse removeActivation(String activationId, String externalUserId) throws RemoteException {
479+
return this.removeActivation(activationId, externalUserId, false);
480+
}
481+
482+
/**
483+
* Call the removeActivation method of the PowerAuth 3.0 Server SOAP interface.
484+
* @param activationId Activation ID of activation to be removed.
485+
* @param externalUserId User ID of user who removed the activation. Use null value if activation owner caused the change.
486+
* @param revokeRecoveryCodes Indicates if the recovery codes associated with this activation should be also revoked.
487+
* @return {@link io.getlime.powerauth.soap.v3.PowerAuthPortV3ServiceStub.RemoveActivationResponse}
488+
* @throws RemoteException In case of a business logic error.
489+
*/
490+
public PowerAuthPortV3ServiceStub.RemoveActivationResponse removeActivation(String activationId, String externalUserId, Boolean revokeRecoveryCodes) throws RemoteException {
479491
PowerAuthPortV3ServiceStub.RemoveActivationRequest request = new PowerAuthPortV3ServiceStub.RemoveActivationRequest();
480492
request.setActivationId(activationId);
481493
request.setExternalUserId(externalUserId);
494+
request.setRevokeRecoveryCodes(revokeRecoveryCodes);
482495
return this.removeActivation(request);
483496
}
484497

powerauth-java-client-axis/src/main/resources/soap/wsdl/serviceV3.wsdl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@
448448
<xs:sequence>
449449
<xs:element maxOccurs="1" minOccurs="1" name="activationId" type="xs:string"/>
450450
<xs:element maxOccurs="1" minOccurs="0" name="externalUserId" type="xs:string"/>
451+
<xs:element maxOccurs="1" minOccurs="0" name="revokeRecoveryCodes" type="xs:boolean"/>
451452
</xs:sequence>
452453
</xs:complexType>
453454
</xs:element>

powerauth-java-client-spring/src/main/java/io/getlime/security/powerauth/soap/spring/client/PowerAuthServiceClient.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,21 @@ public RemoveActivationResponse removeActivation(RemoveActivationRequest request
344344
* @return {@link RemoveActivationResponse}
345345
*/
346346
public RemoveActivationResponse removeActivation(String activationId, String externalUserId) {
347+
return this.removeActivation(activationId, externalUserId, false);
348+
}
349+
350+
/**
351+
* Call the removeActivation method of the PowerAuth 3.0 Server SOAP interface.
352+
* @param activationId Activation ID of activation to be removed.
353+
* @param externalUserId User ID of user who removed the activation. Use null value if activation owner caused the change.
354+
* @param revokeRecoveryCodes Indicates if the recovery codes associated with this activation should be also revoked.
355+
* @return {@link RemoveActivationResponse}
356+
*/
357+
public RemoveActivationResponse removeActivation(String activationId, String externalUserId, Boolean revokeRecoveryCodes) {
347358
RemoveActivationRequest request = new RemoveActivationRequest();
348359
request.setActivationId(activationId);
349360
request.setExternalUserId(externalUserId);
361+
request.setRevokeRecoveryCodes(revokeRecoveryCodes);
350362
return this.removeActivation(request);
351363
}
352364

powerauth-java-client-spring/src/main/resources/soap/wsdl/serviceV3.wsdl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@
448448
<xs:sequence>
449449
<xs:element maxOccurs="1" minOccurs="1" name="activationId" type="xs:string"/>
450450
<xs:element maxOccurs="1" minOccurs="0" name="externalUserId" type="xs:string"/>
451+
<xs:element maxOccurs="1" minOccurs="0" name="revokeRecoveryCodes" type="xs:boolean"/>
451452
</xs:sequence>
452453
</xs:complexType>
453454
</xs:element>

powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/database/repository/RecoveryCodeRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ public interface RecoveryCodeRepository extends CrudRepository<RecoveryCodeEntit
4949
@Query("SELECT r FROM RecoveryCodeEntity r WHERE r.userId = :userId ORDER BY r.timestampCreated DESC")
5050
List<RecoveryCodeEntity> findAllByUserId(String userId);
5151

52+
/**
53+
* Find all recovery codes for given activation ID.
54+
* @param activationId Activation ID.
55+
* @return Recovery codes matching search criteria.
56+
*/
57+
@Query("SELECT r FROM RecoveryCodeEntity r WHERE r.activationId = :activationId ORDER BY r.timestampCreated DESC")
58+
List<RecoveryCodeEntity> findAllByActivationId(String activationId);
59+
5260
/**
5361
* Find all recovery codes for given application ID and user ID.
5462
* @param applicationId Application ID.

powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/v3/ActivationServiceBehavior.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,10 +1095,11 @@ public CommitActivationResponse commitActivation(String activationId, String ext
10951095
*
10961096
* @param activationId Activation ID.
10971097
* @param externalUserId User ID of user who removed the activation. Use null value if activation owner caused the change.
1098+
* @param revokeRecoveryCodes Flag that indicates if a recover codes associated with this activation should be also revoked.
10981099
* @return Response with confirmation of removal.
10991100
* @throws GenericServiceException In case activation does not exist.
11001101
*/
1101-
public RemoveActivationResponse removeActivation(String activationId, String externalUserId) throws GenericServiceException {
1102+
public RemoveActivationResponse removeActivation(String activationId, String externalUserId, boolean revokeRecoveryCodes) throws GenericServiceException {
11021103
ActivationRecordEntity activation = repositoryCatalogue.getActivationRepository().findActivationWithLock(activationId);
11031104
if (activation != null) { // does the record even exist?
11041105
activation.setActivationStatus(io.getlime.security.powerauth.app.server.database.model.ActivationStatus.REMOVED);
@@ -1107,6 +1108,26 @@ public RemoveActivationResponse removeActivation(String activationId, String ext
11071108
RemoveActivationResponse response = new RemoveActivationResponse();
11081109
response.setActivationId(activationId);
11091110
response.setRemoved(true);
1111+
if (revokeRecoveryCodes) {
1112+
final RecoveryCodeRepository recoveryCodeRepository = repositoryCatalogue.getRecoveryCodeRepository();
1113+
final List<RecoveryCodeEntity> recoveryCodeEntities = recoveryCodeRepository.findAllByActivationId(activationId);
1114+
final Date now = new Date();
1115+
for (RecoveryCodeEntity recoveryCode : recoveryCodeEntities) {
1116+
// revoke only codes that are not yet revoked, to avoid messing up with timestamp
1117+
if (!RecoveryCodeStatus.REVOKED.equals(recoveryCode.getStatus())) {
1118+
recoveryCode.setStatus(RecoveryCodeStatus.REVOKED);
1119+
recoveryCode.setTimestampLastChange(now);
1120+
// Change status of PUKs with status VALID to INVALID
1121+
for (RecoveryPukEntity puk : recoveryCode.getRecoveryPuks()) {
1122+
if (RecoveryPukStatus.VALID.equals(puk.getStatus())) {
1123+
puk.setStatus(RecoveryPukStatus.INVALID);
1124+
puk.setTimestampLastChange(now);
1125+
}
1126+
}
1127+
recoveryCodeRepository.save(recoveryCode);
1128+
}
1129+
}
1130+
}
11101131
return response;
11111132
} else {
11121133
logger.info("Activation does not exist, activation ID: {}", activationId);
@@ -1339,19 +1360,7 @@ public RecoveryCodeActivationResponse createActivationUsingRecoveryCode(Recovery
13391360

13401361
// If recovery code is bound to an existing activation, remove this activation
13411362
if (recoveryCodeEntity.getActivationId() != null) {
1342-
removeActivation(recoveryCodeEntity.getActivationId(), null);
1343-
// If there are no PUKs in VALID state left, set the recovery code status to REVOKED
1344-
boolean validPukExists = false;
1345-
for (RecoveryPukEntity recoveryPukEntity : recoveryCodeEntity.getRecoveryPuks()) {
1346-
if (RecoveryPukStatus.VALID.equals(recoveryPukEntity.getStatus())) {
1347-
validPukExists = true;
1348-
break;
1349-
}
1350-
}
1351-
if (!validPukExists) {
1352-
recoveryCodeEntity.setStatus(RecoveryCodeStatus.REVOKED);
1353-
recoveryCodeEntity.setTimestampLastChange(new Date());
1354-
}
1363+
removeActivation(recoveryCodeEntity.getActivationId(), null, true);
13551364
}
13561365

13571366
// Persist recovery code changes

powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/v3/RecoveryServiceBehavior.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ public LookupRecoveryCodesResponse lookupRecoveryCodes(LookupRecoveryCodesReques
423423
} else if (userId != null) {
424424
// User ID is specified
425425
recoveryCodesEntities = recoveryCodeRepository.findAllByUserId(userId);
426+
} else if (activationId != null) {
427+
// Activation ID is specified
428+
recoveryCodesEntities = recoveryCodeRepository.findAllByActivationId(activationId);
426429
} else {
427430
// Only application ID is specified, such request is not allowed
428431
logger.warn("Invalid request for lookup of recovery codes");

powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/v3/PowerAuthServiceImpl.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,13 @@ public RemoveActivationResponse removeActivation(RemoveActivationRequest request
468468
try {
469469
String activationId = request.getActivationId();
470470
String externalUserId = request.getExternalUserId();
471-
logger.info("RemoveActivationRequest received, activation ID: {}", activationId);
472-
RemoveActivationResponse response = behavior.getActivationServiceBehavior().removeActivation(activationId, externalUserId);
471+
Boolean revokeRecoveryCodes = request.isRevokeRecoveryCodes();
472+
if (revokeRecoveryCodes == null) {
473+
// The default value is false for revokeRecoveryCodes
474+
revokeRecoveryCodes = false;
475+
}
476+
logger.info("RemoveActivationRequest received, activation ID: {}, revoke recovery codes: {}", activationId, revokeRecoveryCodes);
477+
RemoveActivationResponse response = behavior.getActivationServiceBehavior().removeActivation(activationId, externalUserId, revokeRecoveryCodes);
473478
logger.info("RemoveActivationRequest succeeded");
474479
return response;
475480
} catch (GenericServiceException ex) {

powerauth-java-server/src/main/resources/xsd/PowerAuth-3.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@
454454
<xs:sequence>
455455
<xs:element name="activationId" type="xs:string" minOccurs="1" maxOccurs="1"/>
456456
<xs:element name="externalUserId" type="xs:string" minOccurs="0" maxOccurs="1"/>
457+
<xs:element name="revokeRecoveryCodes" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
457458
</xs:sequence>
458459
</xs:complexType>
459460
</xs:element>

0 commit comments

Comments
 (0)