Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSv3 - schedule a root CA refresh after the field is updated #9870

Open
wants to merge 2 commits into
base: issv3-2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion java/code/src/com/suse/manager/hub/HubController.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@
import com.suse.manager.model.hub.OrgInfoJson;
import com.suse.manager.model.hub.RegisterJson;
import com.suse.manager.model.hub.SCCCredentialsJson;
import com.suse.manager.model.hub.UpdatableServerData;
import com.suse.manager.webui.controllers.ECMAScriptDateAdapter;
import com.suse.manager.webui.utils.token.TokenBuildingException;
import com.suse.manager.webui.utils.token.TokenParsingException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
Expand Down Expand Up @@ -143,7 +146,8 @@ private String scheduleProductRefresh(Request request, Response response, IssAcc
}

private String setHubDetails(Request request, Response response, IssAccessToken accessToken) {
Map<String, String> data = GSON.fromJson(request.body(), Map.class);
Type mapType = new TypeToken<Map<String, String>>() { }.getType();
UpdatableServerData data = new UpdatableServerData(GSON.fromJson(request.body(), mapType));

try {
hubManager.updateServerData(accessToken, accessToken.getServerFqdn(), IssRole.HUB, data);
Expand All @@ -152,6 +156,10 @@ private String setHubDetails(Request request, Response response, IssAccessToken
LOGGER.error("Invalid data provided: ", ex);
return badRequest(response, "Invalid data");
}
catch (TaskomaticApiException ex) {
LOGGER.error("Unable to schedule Taskomatic execution to refresh the root ca: ", ex);
return internalServerError(response, "Unable to schedule refresh of the root CA certificate");
}
return success(response);
}

Expand Down
59 changes: 28 additions & 31 deletions java/code/src/com/suse/manager/hub/HubManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import com.suse.manager.model.hub.ManagerInfoJson;
import com.suse.manager.model.hub.ModifyCustomChannelInfoJson;
import com.suse.manager.model.hub.TokenType;
import com.suse.manager.model.hub.UpdatableServerData;
import com.suse.manager.webui.controllers.ProductsController;
import com.suse.manager.webui.utils.token.IssTokenBuilder;
import com.suse.manager.webui.utils.token.Token;
Expand All @@ -74,7 +75,6 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

Expand Down Expand Up @@ -528,7 +528,8 @@ public ManagerInfoJson collectManagerInfo(IssAccessToken accessToken) {
* @param role the role which should be changed
* @param data the new data
*/
public void updateServerData(IssAccessToken token, String fqdn, IssRole role, Map<String, String> data) {
public void updateServerData(IssAccessToken token, String fqdn, IssRole role, UpdatableServerData data)
throws TaskomaticApiException {
ensureValidToken(token);
updateServerData(fqdn, role, data);
}
Expand All @@ -540,41 +541,37 @@ public void updateServerData(IssAccessToken token, String fqdn, IssRole role, Ma
* @param fqdn the FQDN identifying the Hub or Peripheral Server
* @param role the role which should be changed
* @param data the new data
* @throws TaskomaticApiException when it's not possible to schedule the certificate refresh
*/
public void updateServerData(User user, String fqdn, IssRole role, Map<String, String> data) {
public void updateServerData(User user, String fqdn, IssRole role, UpdatableServerData data)
throws TaskomaticApiException {
ensureSatAdmin(user);
updateServerData(fqdn, role, data);
}

private void updateServerData(String fqdn, IssRole role, Map<String, String> data) {
switch (role) {
case HUB -> hubFactory.lookupIssHubByFqdn(fqdn).ifPresentOrElse(issHub -> {
if (data.containsKey("root_ca")) {
issHub.setRootCa(data.get("root_ca"));
}
if (data.containsKey("gpg_key")) {
issHub.setGpgKey(data.get("gpg_key"));
}
hubFactory.save(issHub);
},
() -> {
LOG.error("Server {} not found with role {}", fqdn, role);
throw new IllegalArgumentException("Server not found");
});
case PERIPHERAL -> hubFactory.lookupIssPeripheralByFqdn(fqdn).ifPresentOrElse(issPeripheral -> {
if (data.containsKey("root_ca")) {
issPeripheral.setRootCa(data.get("root_ca"));
}
hubFactory.save(issPeripheral);
},
()-> {
LOG.error("Server {} not found with role {}", fqdn, role);
throw new IllegalArgumentException("Server not found");
});
default -> {
LOG.error("Unknown role {}", role);
throw new IllegalArgumentException("Unknown role");
private void updateServerData(String fqdn, IssRole role, UpdatableServerData data) throws TaskomaticApiException {
Optional<? extends IssServer> server = switch (role) {
case HUB -> hubFactory.lookupIssHubByFqdn(fqdn);
case PERIPHERAL -> hubFactory.lookupIssPeripheralByFqdn(fqdn);
};

server.ifPresentOrElse(issServer -> {
if (data.hasRootCA()) {
issServer.setRootCa(data.getRootCA());
}

if (data.hasGpgKey() && issServer instanceof IssHub issHub) {
issHub.setGpgKey(data.getGpgKey());
}

hubFactory.save(issServer);
}, () -> {
LOG.error("Server {} not found with role {}", fqdn, role);
throw new IllegalArgumentException("Server not found");
});

if (data.hasRootCA()) {
taskomaticApi.scheduleSingleRootCaCertUpdate(computeRootCaFileName(role, fqdn), data.getRootCA());
}
}

Expand Down
8 changes: 6 additions & 2 deletions java/code/src/com/suse/manager/hub/test/HubManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import com.suse.manager.model.hub.IssServer;
import com.suse.manager.model.hub.ManagerInfoJson;
import com.suse.manager.model.hub.TokenType;
import com.suse.manager.model.hub.UpdatableServerData;
import com.suse.manager.webui.services.iface.MonitoringManager;
import com.suse.manager.webui.services.iface.SaltApi;
import com.suse.manager.webui.services.test.TestSaltApi;
Expand Down Expand Up @@ -830,8 +831,11 @@ public void canUpdateServerDetails() throws TokenBuildingException, TaskomaticAp
assertEquals("---- BEGIN ROOT CA ----", hub.getRootCa());
assertEquals("---- BEGIN GPG PUB KEY -----", hub.getGpgKey());

Map<String, String> data = Map.of("gpg_key", "---- BEGIN NEW GPG PUB KEY -----",
"root_ca", "---- BEGIN NEW ROOT CA ----");
UpdatableServerData data = new UpdatableServerData(Map.of(
"gpg_key", "---- BEGIN NEW GPG PUB KEY -----",
"root_ca", "---- BEGIN NEW ROOT CA ----")
);

hubManager.updateServerData(satAdmin, "hub.domain.com", IssRole.valueOf("HUB"), data);
HibernateFactory.getSession().flush();
HibernateFactory.getSession().clear();
Expand Down
13 changes: 3 additions & 10 deletions java/code/src/com/suse/manager/model/hub/HubFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,12 @@ protected Logger getLogger() {

/**
* Save a {@link IssHub} object
* @param issHubIn object to save
* @param issServer object to save
*/
public void save(IssHub issHubIn) {
saveObject(issHubIn);
public void save(IssServer issServer) {
saveObject(issServer);
}

/**
* Save a {@link IssPeripheral} object
* @param issPeripheralIn object to save
*/
public void save(IssPeripheral issPeripheralIn) {
saveObject(issPeripheralIn);
}

/**
* Save a {@link IssPeripheralChannels} object
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2025 SUSE LLC
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*/

package com.suse.manager.model.hub;

import java.util.Map;

public class UpdatableServerData {
private final boolean rootCADefined;

private final String rootCA;

private final boolean gpgKeyDefined;

private final String gpgKey;

/**
* Builds an instance from the given map
* @param dataMap the map containing the new values. null as value is supported.
*/
public UpdatableServerData(Map<String, String> dataMap) {
this.rootCADefined = dataMap.containsKey("root_ca");
this.rootCA = dataMap.get("root_ca");
this.gpgKeyDefined = dataMap.containsKey("gpg_key");
this.gpgKey = dataMap.get("gpg_key");
}

/**
* Check if the root CA is defined
* @return true if the root ca is part of this object
*/
public boolean hasRootCA() {
return rootCADefined;
}

/**
* Retrieves the value of the root CA, possibly null.
* @return the value of the root CA.
* @throws IllegalStateException if the field is not defined in this object.
* Use {@link #hasRootCA()} to check beforehand.
*/
public String getRootCA() {
if (!rootCADefined) {
throw new IllegalStateException("rootCA is not defined");
}

return rootCA;
}

/**
* Check if the GPG key is defined
* @return true if the GPG key is part of this object
*/
public boolean hasGpgKey() {
return gpgKeyDefined;
}

/**
* Returns the value of the GPG key, possibly null.
* @return the value of the GPG key
* @throws IllegalStateException if the field is not defined in this object
* Use {@link #hasGpgKey()} to check beforehand.
*/
public String getGpgKey() {
if (!gpgKeyDefined) {
throw new IllegalStateException("gpgKey is not defined");
}

return gpgKey;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.suse.manager.model.hub.IssRole;
import com.suse.manager.model.hub.IssServer;
import com.suse.manager.model.hub.TokenType;
import com.suse.manager.model.hub.UpdatableServerData;
import com.suse.manager.webui.controllers.ECMAScriptDateAdapter;
import com.suse.manager.webui.controllers.admin.beans.CreateTokenRequest;
import com.suse.manager.webui.controllers.admin.beans.HubRegisterRequest;
Expand Down Expand Up @@ -63,7 +64,6 @@
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLException;

Expand Down Expand Up @@ -331,9 +331,14 @@ private String updateServerRootCA(Request request, Response response, User user,
return badRequest(response, LOC.getMessage("hub.cannot_find_server"));
}

// Collections.singletonMap() is used in place of Map.of() because it allows null as value
Map<String, String> dataMap = Collections.singletonMap("root_ca", rootCA);
hubManager.updateServerData(user, server.getFqdn(), role, dataMap);
try {
// Collections.singletonMap() is used in place of Map.of() because it allows null as value
UpdatableServerData data = new UpdatableServerData(Collections.singletonMap("root_ca", rootCA));
hubManager.updateServerData(user, server.getFqdn(), role, data);
}
catch (TaskomaticApiException e) {
return internalServerError(response, LOC.getMessage("hub.cannot_refresh_certificate"));
}

return success(response);
}
Expand Down
10 changes: 8 additions & 2 deletions java/code/src/com/suse/manager/xmlrpc/iss/HubHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import com.suse.manager.hub.HubManager;
import com.suse.manager.model.hub.IssRole;
import com.suse.manager.model.hub.UpdatableServerData;
import com.suse.manager.webui.utils.token.TokenBuildingException;
import com.suse.manager.webui.utils.token.TokenException;
import com.suse.manager.webui.utils.token.TokenParsingException;
Expand Down Expand Up @@ -317,7 +318,7 @@ public int registerPeripheralWithToken(User loggedInUser, String fqdn, String to
}
catch (TaskomaticApiException ex) {
LOGGER.error("Unable to schedule root CA certificate update {}", fqdn, ex);
throw new TokenExchangeFailedException(ex);
throw new com.redhat.rhn.frontend.xmlrpc.TaskomaticApiException("Unable to refresh root CA certificate");
}

return 1;
Expand Down Expand Up @@ -396,7 +397,12 @@ public int deregister(User loggedInUser, String fqdn, boolean onlyLocal) {
*/
public int setDetails(User loggedInUser, String fqdn, String role, Map<String, String> data) {
ensureSatAdmin(loggedInUser);
hubManager.updateServerData(loggedInUser, fqdn, IssRole.valueOf(role), data);
try {
hubManager.updateServerData(loggedInUser, fqdn, IssRole.valueOf(role), new UpdatableServerData(data));
}
catch (TaskomaticApiException e) {
throw new com.redhat.rhn.frontend.xmlrpc.TaskomaticApiException("Unable to refresh root CA certificate");
}
return 1;
}
}
Loading