Skip to content

Commit

Permalink
feat(fido2): allow to update device data in SG authentication response
Browse files Browse the repository at this point in the history
…#8116

Signed-off-by: Yuriy Movchan <Yuriy.Movchan@gmail.com>
  • Loading branch information
yurem committed Mar 21, 2024
1 parent 9ec7177 commit 7f10c71
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from java.time.format import DateTimeFormatter
from io.jans.as.model.configuration import AppConfiguration
from io.jans.as.server.service.custom import CustomScriptService
from io.jans.orm.model.fido2 import Fido2DeviceNotificationConf

import sys
import json
Expand Down Expand Up @@ -930,8 +931,7 @@ def getTargetEndpointArn(self, registrationPersistenceService, pushSnsService, p
# Return endpoint ARN if it created already
notificationConf = u2fDevice.getDeviceNotificationConf()
if StringHelper.isNotEmpty(notificationConf):
notificationConfJson = json.loads(notificationConf)
targetEndpointArn = notificationConfJson['sns_endpoint_arn']
targetEndpointArn = notificationConf.getSnsEndpointArn()
if StringHelper.isNotEmpty(targetEndpointArn):
print "Super-Gluu. Get target endpoint ARN. There is already created target endpoint ARN"
return targetEndpointArn
Expand Down Expand Up @@ -977,7 +977,7 @@ def getTargetEndpointArn(self, registrationPersistenceService, pushSnsService, p
# Store created endpoint ARN in device entry
userInum = user.getAttribute("inum")
u2fDeviceUpdate = registrationPersistenceService.findRegisteredUserDevice(userInum, u2fDevice.getId())
u2fDeviceUpdate.setDeviceNotificationConf('{"sns_endpoint_arn" : "%s"}' % targetEndpointArn)
u2fDeviceUpdate.setDeviceNotificationConf(Fido2DeviceNotificationConf(targetEndpointArn, None, None))
registrationPersistenceService.update(u2fDeviceUpdate)
print "Super-Gluu. Send push notification. Stored ARN user's '%s' enpoint " % user.getUserId()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -359,6 +360,23 @@ public ObjectNode verify(JsonNode params) {
authenticationData.setStatus(Fido2AuthenticationStatus.canceled);
} else {
authenticationData.setStatus(Fido2AuthenticationStatus.authenticated);

JsonNode responseDeviceData = responseNode.get("deviceData");
if (responseDeviceData != null && responseDeviceData.isTextual()) {
try {
Fido2DeviceData deviceData = dataMapperService.readValue(
new String(base64Service.urlDecode(responseDeviceData.asText()), StandardCharsets.UTF_8),
Fido2DeviceData.class);

boolean pushTokenUpdated = !StringHelper.equals(registrationEntry.getDeviceData().getPushToken(), deviceData.getPushToken());
if (pushTokenUpdated) {
prepareForPushTokenChange(registrationEntry);
}
registrationEntry.setDeviceData(deviceData);
} catch (Exception ex) {
throw errorResponseFactory.invalidRequest(String.format("Device data is invalid: %s", responseDeviceData), ex);
}
}
}

// Set expiration
Expand Down Expand Up @@ -397,6 +415,28 @@ public ObjectNode verify(JsonNode params) {
return finishResponseNode;
}

private void prepareForPushTokenChange(Fido2RegistrationEntry registrationEntry) {
Fido2DeviceNotificationConf deviceNotificationConf = registrationEntry.getDeviceNotificationConf();
if (deviceNotificationConf == null) {
return;
}

String snsEndpointArn = deviceNotificationConf.getSnsEndpointArn();
if (StringHelper.isEmpty(snsEndpointArn)) {
return;
}

deviceNotificationConf.setSnsEndpointArn(null);
deviceNotificationConf.setSnsEndpointArnRemove(snsEndpointArn);
List<String> snsEndpointArnHistory = deviceNotificationConf.getSnsEndpointArnHistory();
if (snsEndpointArnHistory == null) {
snsEndpointArnHistory = new ArrayList<>();
deviceNotificationConf.setSnsEndpointArnHistory(snsEndpointArnHistory);
}

snsEndpointArnHistory.add(snsEndpointArn);
}

private Pair<ArrayNode, String> prepareAllowedCredentials(String documentDomain, String username, String requestedKeyHandle, boolean superGluu) {
if (appConfiguration.isOldU2fMigrationEnabled()) {
List<DeviceRegistration> existingFidoRegistrations = deviceRegistrationService.findAllRegisteredByUsername(username,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ public ObjectNode buildFido2AssertionStartResponse(String userName, String keyHa
* mYAmH5qk5KMaYATFAryIpoVwARGvEFQTWE2Q","clientData":"eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwi
* Y2hhbGxlbmdlIjoiNVFvUnR1ZG1lajV0cmNyTVJnRkJvSTVyWjZweklaaVlQM3UzYlhDdnZBRSIsIm9yaWdpbiI6Imh0dHBzOlwv
* XC95dXJlbS1lbWVyZ2luZy1waWcuZ2x1dS5pbmZvXC9pZGVudGl0eVwvYXV0aGNvZGUuaHRtIn0","keyHandle":"YJvWD9n40e
* IurInJvPKUoxpKzrleUMWgu9w3v_NUBu7BiGAclgkH_Zg88_T5y6Rh78imTxTh0djWFYG4jxOixw"}
* IurInJvPKUoxpKzrleUMWgu9w3v_NUBu7BiGAclgkH_Zg88_T5y6Rh78imTxTh0djWFYG4jxOixw","deviceData":"eyJuYW1l
* IjoiU00tRzk5MUIiLCJvc19uYW1lIjoidGlyYW1pc3UiLCJvc192ZXJzaW9uIjoiMTMiLCJwbGF0Zm9ybSI6ImFuZHJvaWQiLCJw
* dXNoX3Rva2VuIjoicHVzaF90b2tlbiIsInR5cGUiOiJub3JtYWwiLCJ1dWlkIjoidXVpZCJ9"}
* - response:
* {"status":"success","challenge":"5QoRtudmej5trcrMRgFBoI5rZ6pzIZiYP3u3bXCvvAE"}
*
Expand Down Expand Up @@ -215,6 +217,7 @@ public ObjectNode buildFido2AuthenticationVerifyResponse(String userName, String
// Add response node
ObjectNode response = dataMapperService.createObjectNode();
params.set("response", response);
response.put("deviceData", authenticateResponse.getDeviceData());

// We have to quote URL to conform bug in Super Gluu
response.put("clientDataJSON", base64Service.urlEncodeToString(clientData.toString().replaceAll("/", "\\\\/").getBytes(StandardCharsets.UTF_8)));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text.
*
* Copyright (c) 2020, Janssen Project
*/

package io.jans.orm.model.fido2;

import java.io.Serializable;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* FIDO2 U2F device notification configuration
*
* @author Yuriy Movchan Date: 03/21/2024
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Fido2DeviceNotificationConf implements Serializable {

private static final long serialVersionUID = -8173244116167488365L;

@JsonProperty(value = "sns_endpoint_arn")
private String snsEndpointArn;

@JsonProperty(value = "sns_endpoint_arn_remove")
private String snsEndpointArnRemove;

@JsonProperty(value = "sns_endpoint_arn_history")
private List<String> snsEndpointArnHistory;

public Fido2DeviceNotificationConf(@JsonProperty(value = "sns_endpoint_arn") String snsEndpointArn, @JsonProperty(value = "sns_endpoint_arn_remove") String snsEndpointArnRemove,
@JsonProperty(value = "sns_endpoint_arn_history") List<String> snsEndpointArnHistory) {
this.snsEndpointArn = snsEndpointArn;
this.snsEndpointArnRemove = snsEndpointArnRemove;
this.snsEndpointArnHistory = snsEndpointArnHistory;
}

public String getSnsEndpointArn() {
return snsEndpointArn;
}

public void setSnsEndpointArn(String snsEndpointArn) {
this.snsEndpointArn = snsEndpointArn;
}

public String getSnsEndpointArnRemove() {
return snsEndpointArnRemove;
}

public void setSnsEndpointArnRemove(String snsEndpointArnRemove) {
this.snsEndpointArnRemove = snsEndpointArnRemove;
}

public List<String> getSnsEndpointArnHistory() {
return snsEndpointArnHistory;
}

public void setSnsEndpointArnHistory(List<String> snsEndpointArnHistory) {
this.snsEndpointArnHistory = snsEndpointArnHistory;
}

@Override
public String toString() {
return "Fido2DeviceNotificationConf [snsEndpointArn=" + snsEndpointArn + ", snsEndpointArnRemove="
+ snsEndpointArnRemove + ", snsEndpointArnHistory=" + snsEndpointArnHistory + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ public class Fido2RegistrationEntry extends Fido2Entry implements Serializable {
@AttributeName(name = "jansStatus")
private Fido2RegistrationStatus registrationStatus;

@JsonObject
@AttributeName(name = "jansDeviceNotificationConf")
private String deviceNotificationConf;
private Fido2DeviceNotificationConf deviceNotificationConf;

@JsonObject
@AttributeName(name = "jansDeviceData")
Expand Down Expand Up @@ -92,11 +93,11 @@ public void setRegistrationStatus(Fido2RegistrationStatus registrationStatus) {
this.registrationStatus = registrationStatus;
}

public String getDeviceNotificationConf() {
public Fido2DeviceNotificationConf getDeviceNotificationConf() {
return deviceNotificationConf;
}

public void setDeviceNotificationConf(String deviceNotificationConf) {
public void setDeviceNotificationConf(Fido2DeviceNotificationConf deviceNotificationConf) {
this.deviceNotificationConf = deviceNotificationConf;
}

Expand Down

0 comments on commit 7f10c71

Please sign in to comment.