Skip to content

Commit

Permalink
feat(jans-fido): changes to refactor metadataservers #9111
Browse files Browse the repository at this point in the history
Signed-off-by: shekhar16 <shekharlaad1609@gmail.com>
  • Loading branch information
shekhar16 committed Aug 26, 2024
1 parent 146f4a7 commit 60fe227
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class Fido2Configuration {
private List<RequestedParty> requestedParties = new ArrayList<RequestedParty>();

@DocProperty(description = "String value to provide source of URLs with external metadata")
private String metadataUrlsProvider;
private List<MetadataServer> metadataServers = new ArrayList<MetadataServer>();
@DocProperty(description = "Boolean value indicating whether the MDS download should be omitted")
private boolean disableMetadataService = false;
@DocProperty(description = "Boolean value indicating whether MDS validation should be omitted during attestation")
Expand Down Expand Up @@ -117,14 +117,6 @@ public void setRequestedParties(List<RequestedParty> requestedParties) {
this.requestedParties = requestedParties;
}

public String getMetadataUrlsProvider() {
return metadataUrlsProvider;
}

public void setMetadataUrlsProvider(String metadataUrlsProvider) {
this.metadataUrlsProvider = metadataUrlsProvider;
}

public boolean isSkipValidateMdsInAttestationEnabled() {
return skipValidateMdsInAttestationEnabled;
}
Expand Down Expand Up @@ -172,4 +164,12 @@ public boolean isDisableMetadataService() {
public void setDisableMetadataService(boolean disableMetadataService) {
this.disableMetadataService = disableMetadataService;
}

public List<MetadataServer> getMetadataServers() {
return metadataServers;
}

public void setMetadataServers(List<MetadataServer> metadataServers) {
this.metadataServers = metadataServers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2020, Janssen Project
*/

package io.jans.fido2.model.conf;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.util.ArrayList;
import java.util.List;

/**
* Supported MetadataServer
*
* @author Shekhar L. on 06/08/2024
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataServer {

private String url;

private List<String> certificateDocumentInum = new ArrayList<String>();;


public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}


public List<String> getCertificateDocumentInum() {
return certificateDocumentInum;
}

public void setCertificateDocumentInum(List<String> certificateDocumentInum) {
this.certificateDocumentInum = certificateDocumentInum;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2020, Janssen Project
*/

package io.jans.fido2.service;

import io.jans.fido2.model.conf.AppConfiguration;
import io.jans.fido2.model.conf.Conf;
import io.jans.fido2.service.app.ConfigurationFactory;
import io.jans.orm.PersistenceEntryManager;
import io.jans.orm.exception.BasePersistenceException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.slf4j.Logger;

@ApplicationScoped
public class Fido2Service {

@Inject
Logger logger;

@Inject
PersistenceEntryManager persistenceManager;

@Inject
ConfigurationFactory configurationFactory;

public Conf findConf() {
try {
String configurationDn = configurationFactory.getBaseConfiguration()
.getString("fido2_ConfigurationEntryDN");
return persistenceManager.find(Conf.class, configurationDn);
} catch (BasePersistenceException var3) {
logger.error("Failed to load Fido2 configuration from LDAP");
return null;
}
}

public AppConfiguration find() {
final Conf conf = findConf();
return conf.getDynamicConf();
}

public void mergeConf(Conf conf) {
conf.setRevision(conf.getRevision() + 1);
persistenceManager.merge(conf);
}

public void merge(AppConfiguration fido2ConfigJson) {
Conf conf = this.findConf();
conf.setDynamicConf(fido2ConfigJson);
mergeConf(conf);
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
package io.jans.fido2.service.mds;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.jans.fido2.exception.mds.MdsClientException;
import io.jans.fido2.model.conf.AppConfiguration;
import io.jans.fido2.model.mds.MdsGetEndpointResponse;
import io.jans.fido2.service.DataMapperService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.slf4j.Logger;

import java.util.Collections;
import java.util.Map;

@ApplicationScoped
public class FetchMdsProviderService {

Expand All @@ -40,23 +33,16 @@ public class FetchMdsProviderService {
* @return MetadataTestResponse class
* @throws MdsClientException When an attempt is made to process the json or the status returns other than 200
*/
public MdsGetEndpointResponse fetchMdsV3Endpoints(String endpoint) throws MdsClientException {
public String fetchMdsV3Endpoints(String endpoint) throws MdsClientException {
Client client = clientBuilder.build();
WebTarget target = client.target(endpoint + "/getEndpoints");
Map<String, String> body = Collections.singletonMap("endpoint", appConfiguration.getBaseEndpoint());
WebTarget target = client.target(endpoint);
try {
log.debug("Fetch mds getEndpoints request, body: {}", dataMapperService.writeValueAsString(body));
Response response = target.request().post(Entity.entity(body, MediaType.APPLICATION_JSON_TYPE));
String responseBody = response.readEntity(String.class);
log.debug("Fetch mds getEndpoints response, body: {}", responseBody);
MdsGetEndpointResponse responseEntity = dataMapperService.readValueString(responseBody, MdsGetEndpointResponse.class);
if (!responseEntity.getStatus().equalsIgnoreCase("ok")) {
throw new MdsClientException(String.format("Error getting endpoints from mds test, status: %s, errorMessage: '%s'", responseEntity.getStatus(), responseEntity.getErrorMessage()));
Response response = target.request().get();
if (response.getStatus() != 200) {
throw new MdsClientException(String.format("Error getting endpoints from mds test, status: %s, errorMessage: '%s'", response.getStatus(), response.getStatusInfo().getReasonPhrase()));
}
return responseEntity;
} catch (JsonProcessingException e) {
log.error("Error when processing json: {}", e.getMessage(), e);
throw new MdsClientException("Error when processing json: " + e.getMessage());
String responseBody = response.readEntity(String.class);
return responseBody;
} finally {
client.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package io.jans.fido2.service.mds;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.api.client.util.ArrayMap;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSObject;
Expand All @@ -20,12 +21,16 @@
import io.jans.fido2.exception.mds.MdsClientException;
import io.jans.fido2.model.conf.AppConfiguration;
import io.jans.fido2.model.conf.Fido2Configuration;
import io.jans.fido2.model.mds.MdsGetEndpointResponse;
import io.jans.fido2.model.conf.MetadataServer;
import io.jans.fido2.service.Base64Service;
import io.jans.fido2.service.CertificateService;
import io.jans.fido2.service.DataMapperService;
import io.jans.fido2.service.Fido2Service;
import io.jans.fido2.service.app.ConfigurationFactory;
import io.jans.fido2.service.verifier.CertificateVerifier;
import io.jans.service.cdi.event.ApplicationInitialized;
import io.jans.service.document.store.service.DBDocumentService;
import io.jans.service.document.store.service.Document;
import io.jans.util.Pair;
import io.jans.util.StringHelper;
import jakarta.enterprise.context.ApplicationScoped;
Expand Down Expand Up @@ -76,10 +81,19 @@ public class TocService {

@Inject
private AppConfiguration appConfiguration;

@Inject
private ConfigurationFactory configurationFactory;

@Inject
private FetchMdsProviderService fetchMdsProviderService;

@Inject
private DBDocumentService dbDocumentService;

@Inject
private Fido2Service fido2Service;

private Map<String, JsonNode> tocEntries;

private LocalDate nextUpdate;
Expand Down Expand Up @@ -286,28 +300,40 @@ public boolean downloadMdsFromServer(URL metadataUrl) {
}

private void loadMetadataServiceExternalProvider() {
String metadataUrlsProvider = appConfiguration.getFido2Configuration().getMetadataUrlsProvider();
if (metadataUrlsProvider != null && !metadataUrlsProvider.trim().isEmpty()) {
log.debug("MetadataUrlsProvider found: {}", metadataUrlsProvider);
List<MetadataServer> metadataServers = appConfiguration.getFido2Configuration().getMetadataServers();
Map<String, List<String>> updatedmetadataServers = new HashMap<>();
if (metadataServers != null && !metadataServers.isEmpty()) {
log.debug("metadataServers found: {}", metadataServers.size());
try {
MdsGetEndpointResponse mdsGetEndpointResponse = fetchMdsProviderService.fetchMdsV3Endpoints(metadataUrlsProvider);
Fido2Configuration fido2Configuration = appConfiguration.getFido2Configuration();
String mdsTocRootCertsFolder = fido2Configuration.getMdsCertsFolder();
List<Map<String, JsonNode>> entryList = new ArrayList<>();
for (String mdsUrl : mdsGetEndpointResponse.getResult()) {
String blobJwt = fetchMdsProviderService.fetchMetadataBlob(mdsUrl);
if (blobJwt == null) {
continue;
}
for(MetadataServer metadataServer : metadataServers) {
String blobJWT = fetchMdsProviderService.fetchMdsV3Endpoints(metadataServer.getUrl());
Fido2Configuration fido2Configuration = appConfiguration.getFido2Configuration();
String mdsTocRootCertsFolder = fido2Configuration.getMdsCertsFolder();
List <String> documentsId = saveMetadataServerCertsInDB(metadataServer.getUrl(), blobJWT);
updatedmetadataServers.put(metadataServer.getUrl(),documentsId);
List<Map<String, JsonNode>> entryList = new ArrayList<>();
try {
Pair<LocalDate,Map<String, JsonNode>> dateMapPair = readEntriesFromTocJWT(blobJwt, mdsTocRootCertsFolder, false);
Pair<LocalDate, Map<String, JsonNode>> dateMapPair = readEntriesFromTocJWT(blobJWT, mdsTocRootCertsFolder, false);
entryList.add(dateMapPair.getSecond());
} catch (Fido2RuntimeException e) {
log.error(e.getMessage());
}
this.tocEntries.putAll(mergeAndResolveDuplicateEntries(entryList));
log.info("🔐 MedataUrlsProvider successfully loaded");
}
this.tocEntries.putAll(mergeAndResolveDuplicateEntries(entryList));
log.info("🔐 MedataUrlsProvider successfully loaded");

List <MetadataServer> metadataServerList = new ArrayList<>();

for(String metadataserverurl : updatedmetadataServers.keySet()){
MetadataServer metadataServer = new MetadataServer();
metadataServer.setUrl(metadataserverurl);
metadataServer.setCertificateDocumentInum(updatedmetadataServers.get(metadataserverurl));
metadataServerList.add(metadataServer);
}

AppConfiguration updateAppConfiguration = configurationFactory.getAppConfiguration();
updateAppConfiguration.getFido2Configuration().setMetadataServers(metadataServerList);
fido2Service.merge(updateAppConfiguration);

} catch (MdsClientException e) {
log.error(e.getMessage());
Expand All @@ -317,6 +343,49 @@ private void loadMetadataServiceExternalProvider() {
}
}

public List<String> saveMetadataServerCertsInDB(String metadataServer, String blobJWT) {
List<String> result = new ArrayList<>();
log.debug("Attempting reading entries from JWT: {}", StringUtils.abbreviateMiddle(blobJWT, "...", 100));
JWSObject blobDecoded;
try {
blobDecoded = JWSObject.parse(blobJWT);
} catch (ParseException e) {
throw new Fido2RuntimeException("Error when parsing TOC JWT: " + e.getMessage(), e);
}
List<String> headerCertificatesX5c = blobDecoded.getHeader().getX509CertChain().stream()
.map(c -> base64Service.encodeToString(c.decode()))
.collect(Collectors.toList());
int index = 0;
if (!headerCertificatesX5c.isEmpty()){
List<Document> oldCerts = dbDocumentService.searchDocuments(metadataServer, 100);
for (Document certDoc : oldCerts) {
try {
dbDocumentService.removeDocument(certDoc);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

for (String cert : headerCertificatesX5c) {
Document document = new Document();
document.setDisplayName(metadataServer + "_" + (index++));
document.setDescription("metadata certificate for " + metadataServer);
document.setJansService(new ArrayList<>(Arrays.asList("Fido2 MDS")));
try {
document.setDocument(cert);
document.setInum(dbDocumentService.generateInumForNewDocument());
document.setDn(dbDocumentService.getDnForDocument(document.getInum()));
document.setJansEnabled(true);
dbDocumentService.addDocument(document);
result.add(document.getInum());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
return result;
}

private Pair<LocalDate, Map<String, JsonNode>> readEntriesFromTocJWT(String tocJwt, String mdsTocRootCertsFolder, boolean loadGlobalVariables) {
log.debug("Attempting reading entries from JWT: {}", StringUtils.abbreviateMiddle(tocJwt, "...", 100));
JWSObject blobDecoded;
Expand Down
Loading

0 comments on commit 60fe227

Please sign in to comment.