Skip to content

Commit

Permalink
Added new /iss path for v3 APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
mackdk committed Dec 13, 2024
1 parent 2142bbc commit d8d0b64
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2024 SUSE LLC
* Copyright (c) 2009--2015 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
Expand All @@ -21,11 +22,11 @@
import com.suse.manager.api.HttpApiRegistry;
import com.suse.manager.webui.utils.LoginHelper;

import org.apache.commons.collections.set.UnmodifiableSet;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;

import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

Expand All @@ -40,17 +41,17 @@ public class PxtAuthenticationService extends BaseAuthenticationService {

public static final long MAX_URL_LENGTH = 2048;

private static final Set UNPROTECTED_URIS;
private static final Set POST_UNPROTECTED_URIS;
private static final Set LOGIN_URIS;
private static final Set<String> UNPROTECTED_URIS;
private static final Set<String> POST_UNPROTECTED_URIS;
private static final Set<String> LOGIN_URIS;

static {
// Login routes
TreeSet set = new TreeSet<>();
TreeSet<String> set = new TreeSet<>();
set.add("/rhn/newlogin/");
set.add("/rhn/manager/login");

LOGIN_URIS = UnmodifiableSet.decorate(set);
LOGIN_URIS = Collections.unmodifiableSet(set);

// Unauthenticated routes
set = new TreeSet<>(set);
Expand All @@ -69,11 +70,12 @@ public class PxtAuthenticationService extends BaseAuthenticationService {
set.add("/rhn/ResetLink");
set.add("/rhn/ResetPasswordSubmit");
set.add("/rhn/saltboot");
set.add("/rhn/iss");

// HTTP API public endpoints
set.addAll(HttpApiRegistry.getUnautenticatedRoutes());

UNPROTECTED_URIS = UnmodifiableSet.decorate(set);
UNPROTECTED_URIS = Collections.unmodifiableSet(set);

// CSRF whitelist
set = new TreeSet<>(set);
Expand All @@ -83,7 +85,7 @@ public class PxtAuthenticationService extends BaseAuthenticationService {
set.add("/rhn/manager/api/");
set.add("/rhn/manager/upload/image");

POST_UNPROTECTED_URIS = UnmodifiableSet.decorate(set);
POST_UNPROTECTED_URIS = Collections.unmodifiableSet(set);
}

private PxtSessionDelegate pxtDelegate;
Expand All @@ -92,17 +94,17 @@ protected PxtAuthenticationService() {
}

@Override
protected Set getLoginURIs() {
protected Set<String> getLoginURIs() {
return LOGIN_URIS;
}

@Override
protected Set getUnprotectedURIs() {
protected Set<String> getUnprotectedURIs() {
return UNPROTECTED_URIS;
}

@Override
protected Set getPostUnprotectedURIs() {
protected Set<String> getPostUnprotectedURIs() {
return POST_UNPROTECTED_URIS;
}

Expand All @@ -125,9 +127,6 @@ public boolean skipCsfr(HttpServletRequest request) {
return requestURIdoesLogin(request) || requestPostCsfrWhitelist(request);
}

/**
* {@inheritDoc}
*/
@Override
public boolean validate(HttpServletRequest request, HttpServletResponse response) {
if (requestURIRequiresAuthentication(request)) {
Expand All @@ -140,9 +139,6 @@ public boolean validate(HttpServletRequest request, HttpServletResponse response
}


/**
* {@inheritDoc}
*/
@Override
public void refresh(HttpServletRequest request, HttpServletResponse response) {
// If URL requires auth and we are authenticated refresh the session.
Expand All @@ -159,9 +155,6 @@ private boolean isAuthenticationRequired(HttpServletRequest request) {
pxtDelegate.getWebUserId(request) == null);
}

/**
* {@inheritDoc}
*/
@Override
public void redirectToLogin(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
Expand Down Expand Up @@ -198,19 +191,12 @@ public void redirectToLogin(HttpServletRequest request, HttpServletResponse resp
}
}

/**
* {@inheritDoc}
*/
@Override
public void redirectTo(HttpServletRequest request, HttpServletResponse response,
String path) {
public void redirectTo(HttpServletRequest request, HttpServletResponse response, String path) {
response.setHeader("Location", path);
response.setStatus(response.SC_SEE_OTHER);
response.setStatus(HttpServletResponse.SC_SEE_OTHER);
}

/**
* {@inheritDoc}
*/
@Override
public void invalidate(HttpServletRequest request, HttpServletResponse response) {
pxtDelegate.invalidatePxtSession(request, response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2024 SUSE LLC
* Copyright (c) 2009--2013 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
Expand Down Expand Up @@ -26,6 +27,7 @@
import org.apache.struts.action.ActionMessages;

import java.io.IOException;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
Expand All @@ -41,27 +43,23 @@
*/
public class EnvironmentFilter implements Filter {

private static Logger log = LogManager.getLogger(EnvironmentFilter.class);
private static final Logger LOGGER = LogManager.getLogger(EnvironmentFilter.class);

private static String[] nosslurls = {"/rhn/kickstart/DownloadFile",
"/rhn/common/DownloadFile",
"/rhn/rpc/api",
"/rhn/errors",
"/rhn/ty/TinyUrl",
"/rhn/websocket",
"/rhn/metrics"};
private static final List<String> NO_SSL_URL = List.of(
"/rhn/kickstart/DownloadFile",
"/rhn/common/DownloadFile",
"/rhn/rpc/api",
"/rhn/errors",
"/rhn/ty/TinyUrl",
"/rhn/websocket",
"/rhn/metrics"
);

/**
* {@inheritDoc}
*/
@Override
public void init(FilterConfig arg0) {
// Not needed in this filter
}

/**
* {@inheritDoc}
*/
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
Expand All @@ -80,8 +78,8 @@ public void doFilter(ServletRequest request,
// Have to make this decision here, because once we pass the request
// off to the next filter, that filter can do work that sends data to
// the client, meaning that we can't redirect.
if (ConfigDefaults.get().isSsl() && RhnHelper.pathNeedsSecurity(nosslurls, path) && !hreq.isSecure()) {
log.debug("redirecting to secure: {}", path);
if (ConfigDefaults.get().isSsl() && RhnHelper.pathNeedsSecurity(NO_SSL_URL, path) && !hreq.isSecure()) {
LOGGER.debug("redirecting to secure: {}", path);
redirectToSecure(hreq, hres);
return;
}
Expand All @@ -90,7 +88,7 @@ public void doFilter(ServletRequest request,
HttpServletRequest req = (HttpServletRequest) request;
request.setAttribute(RequestContext.REQUESTED_URI, req.getRequestURI());

log.debug("set REQUESTED_URI: {}", req.getRequestURI());
LOGGER.debug("set REQUESTED_URI: {}", req.getRequestURI());

// add messages that were put on the request path.
addParameterizedMessages(req);
Expand All @@ -117,9 +115,6 @@ private void addParameterizedMessages(HttpServletRequest req) {
}
}

/**
* {@inheritDoc}
*/
@Override
public void destroy() {
// Nothing to do here
Expand Down
12 changes: 7 additions & 5 deletions java/code/src/com/redhat/rhn/frontend/struts/RhnHelper.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2024 SUSE LLC
* Copyright (c) 2009--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
Expand All @@ -20,6 +21,8 @@
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.DynaActionForm;

import java.util.List;

import javax.servlet.http.HttpServletRequest;


Expand Down Expand Up @@ -57,15 +60,14 @@ private RhnHelper() {
/**
* If the path doesn't require authentication, return false. Otherwise
* return true. Checks that the passed in path doesn't startwith the params
* found in nosecurityPaths
* @param nosecurityPaths array of String paths, "/foo",
* found in noSecurityPaths
* @param noSecurityPaths list of String paths, "/foo",
* "/bar/baz/test.jsp", "/somepath/foo.do"
* @param path to check
* @return boolean if it needs to be authorized or not
*/
public static boolean pathNeedsSecurity(String[] nosecurityPaths,
String path) {
for (String curr : nosecurityPaths) {
public static boolean pathNeedsSecurity(List<String> noSecurityPaths, String path) {
for (String curr : noSecurityPaths) {
if (path.startsWith(curr)) {
return false;
}
Expand Down
62 changes: 62 additions & 0 deletions java/code/src/com/suse/manager/iss/SyncController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 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.iss;

import static com.suse.manager.webui.utils.SparkApplicationHelper.asJson;
import static com.suse.manager.webui.utils.SparkApplicationHelper.json;
import static com.suse.manager.webui.utils.SparkApplicationHelper.usingTokenAuthentication;
import static spark.Spark.post;

import com.suse.manager.webui.controllers.ECMAScriptDateAdapter;
import com.suse.manager.webui.utils.gson.ResultJson;
import com.suse.manager.webui.utils.token.Token;
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.http.HttpStatus;

import java.util.Date;

import spark.Request;
import spark.Response;
import spark.Spark;

public class SyncController {

private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(Date.class, new ECMAScriptDateAdapter())
.serializeNulls()
.create();

/**
* Initialize the API routes
*/
public void initRoutes() {
post("/iss/sync/ping", asJson(usingTokenAuthentication(this::ping)));
}

// Basic ping to check if the system is up
private String ping(Request request, Response response, Token token) {
try {
String fqdn = token.getClaim("fqdn", String.class);
ResultJson<Object> result = ResultJson.successMessage("Pinged from %s".formatted(fqdn));
return json(GSON, response, result, new TypeToken<>() { });
}
catch (TokenParsingException ex) {
Spark.halt(HttpStatus.SC_BAD_REQUEST, "Invalid token provided: missing required claim");
return null;
}
}
}
21 changes: 14 additions & 7 deletions java/code/src/com/suse/manager/webui/Router.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
/*
* Copyright (c) 2015 SUSE LLC
* Copyright (c) 2015--2024 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.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.suse.manager.webui;

Expand All @@ -32,6 +28,7 @@
import com.suse.cloud.CloudPaygManager;
import com.suse.manager.api.HttpApiRegistry;
import com.suse.manager.attestation.AttestationManager;
import com.suse.manager.iss.SyncController;
import com.suse.manager.kubernetes.KubernetesManager;
import com.suse.manager.utils.SaltKeyUtils;
import com.suse.manager.webui.controllers.AnsibleController;
Expand Down Expand Up @@ -253,6 +250,9 @@ public void init() {
// Storybook
StorybookController.initRoutes(jade);

// ISSv3 Sync
initISSv3Routes();

// if the calls above opened Hibernate session, close it now
HibernateFactory.closeSession();
}
Expand Down Expand Up @@ -280,19 +280,26 @@ private void initNotFoundRoutes(JadeTemplateEngine jade) {
});
}

private void initVirtualizationRoutes(JadeTemplateEngine jade, VirtManager virtManager) {
private static void initVirtualizationRoutes(JadeTemplateEngine jade, VirtManager virtManager) {
VirtualGuestsController virtualGuestsController = new VirtualGuestsController(virtManager);
VirtualNetsController virtualNetsController = new VirtualNetsController(virtManager);
VirtualPoolsController virtualPoolsController = new VirtualPoolsController(virtManager);

virtualGuestsController.initRoutes(jade);
virtualNetsController.initRoutes(jade);
virtualPoolsController.initRoutes(jade);
}

private void initContentManagementRoutes(JadeTemplateEngine jade, KubernetesManager kubernetesManager) {
private static void initContentManagementRoutes(JadeTemplateEngine jade, KubernetesManager kubernetesManager) {
ImageBuildController imageBuildController = new ImageBuildController(kubernetesManager);
ImageStoreController.initRoutes(jade);
ImageProfileController.initRoutes(jade);
ImageBuildController.initRoutes(jade, imageBuildController);
}

private static void initISSv3Routes() {
SyncController syncController = new SyncController();

syncController.initRoutes();
}
}
Loading

0 comments on commit d8d0b64

Please sign in to comment.