package org.apereo.cas.mgmt.services.web;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.authentication.principal.ServiceFactory;
import org.apereo.cas.authentication.principal.WebApplicationService;
import org.apereo.cas.mgmt.services.web.beans.RegisteredServiceViewBean;
import org.apereo.cas.mgmt.services.web.factory.RegisteredServiceFactory;
import org.apereo.cas.services.RegexRegisteredService;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* MultiActionController to handle the deletion of RegisteredServices as well as
* displaying them on the Manage Services page.
*
* @author Scott Battaglia
* @since 3.1
*/
@Controller("manageRegisteredServicesMultiActionController")
public class ManageRegisteredServicesMultiActionController extends AbstractManagementController {
private static final Logger LOGGER = LoggerFactory.getLogger(ManageRegisteredServicesMultiActionController.class);
private static final String STATUS = "status";
private RegisteredServiceFactory registeredServiceFactory;
private Service defaultService;
/**
* Instantiates a new manage registered services multi action controller.
*
* @param servicesManager the services manager
* @param registeredServiceFactory the registered service factory
* @param webApplicationServiceFactory the web application service factory
* @param defaultServiceUrl the default service url
*/
public ManageRegisteredServicesMultiActionController(
final ServicesManager servicesManager,
final RegisteredServiceFactory registeredServiceFactory,
final ServiceFactory<WebApplicationService> webApplicationServiceFactory,
final String defaultServiceUrl) {
super(servicesManager);
this.registeredServiceFactory = registeredServiceFactory;
this.defaultService = webApplicationServiceFactory.createService(defaultServiceUrl);
}
/**
* Ensure default service exists.
*/
private void ensureDefaultServiceExists() {
this.servicesManager.load();
final Collection<RegisteredService> c = this.servicesManager.getAllServices();
if (c == null) {
throw new IllegalStateException("Services cannot be empty");
}
if (!this.servicesManager.matchesExistingService(this.defaultService)) {
final RegexRegisteredService svc = new RegexRegisteredService();
svc.setServiceId('^' + this.defaultService.getId());
svc.setName("Services Management Web Application");
svc.setDescription(svc.getName());
this.servicesManager.save(svc);
this.servicesManager.load();
}
}
/**
* Authorization failure handling. Simply returns the view name.
*
* @return the view name.
*/
@GetMapping(value = "/authorizationFailure")
public String authorizationFailureView() {
return "authorizationFailure";
}
/**
* Logout handling. Simply returns the view name.
*
* @param request the request
* @param session the session
* @return the view name.
*/
@GetMapping(value = "/logout")
public String logoutView(final HttpServletRequest request, final HttpSession session) {
LOGGER.debug("Invalidating application session...");
session.invalidate();
return "logout";
}
/**
* Method to delete the RegisteredService by its ID. Will make sure
* the default service that is the management app itself cannot be deleted
* or the user will be locked out.
*
* @param idAsLong the id
* @param response the response
*/
@PostMapping(value = "/deleteRegisteredService")
public void deleteRegisteredService(@RequestParam("id") final long idAsLong,
final HttpServletResponse response) {
final RegisteredService svc = this.servicesManager.findServiceBy(this.defaultService);
if (svc == null || svc.getId() == idAsLong) {
throw new IllegalArgumentException("The default service " + this.defaultService.getId() + " cannot be deleted. "
+ "The definition is required for accessing the application.");
}
final RegisteredService r = this.servicesManager.delete(idAsLong);
if (r == null) {
throw new IllegalArgumentException("Service id " + idAsLong + " cannot be found.");
}
final Map<String, Object> model = new HashMap<>();
model.put("serviceName", r.getName());
model.put(STATUS, HttpServletResponse.SC_OK);
JsonUtils.render(model, response);
}
/**
* Method to show the RegisteredServices.
*
* @param response the response
* @return the Model and View to go to after the services are loaded.
*/
@GetMapping(value = "/manage.html")
public ModelAndView manage(final HttpServletResponse response) {
ensureDefaultServiceExists();
final Map<String, Object> model = new HashMap<>();
model.put("defaultServiceUrl", this.defaultService.getId());
model.put(STATUS, HttpServletResponse.SC_OK);
return new ModelAndView("manage", model);
}
/**
* Gets services.
*
* @param response the response
*/
@GetMapping(value = "/getServices")
public void getServices(final HttpServletResponse response) {
ensureDefaultServiceExists();
final Map<String, Object> model = new HashMap<>();
final List<RegisteredServiceViewBean> serviceBeans = new ArrayList<>();
final List<RegisteredService> services = new ArrayList<>(this.servicesManager.getAllServices());
serviceBeans.addAll(services.stream().map(this.registeredServiceFactory::createServiceViewBean).collect(Collectors.toList()));
model.put("services", serviceBeans);
model.put(STATUS, HttpServletResponse.SC_OK);
JsonUtils.render(model, response);
}
/**
* Updates the {@link RegisteredService#getEvaluationOrder()}.
*
* @param response the response
* @param id the service ids, whose order also determines the service evaluation order
*/
@PostMapping(value = "/updateRegisteredServiceEvaluationOrder")
public void updateRegisteredServiceEvaluationOrder(final HttpServletResponse response,
@RequestParam("id") final long... id) {
if (id == null || id.length == 0) {
throw new IllegalArgumentException("No service id was received. Re-examine the request");
}
for (int i = 0; i < id.length; i++) {
final long svcId = id[i];
final RegisteredService svc = this.servicesManager.findServiceBy(svcId);
if (svc == null) {
throw new IllegalArgumentException("Service id " + svcId + " cannot be found.");
}
svc.setEvaluationOrder(i);
this.servicesManager.save(svc);
}
final Map<String, Object> model = new HashMap<>();
model.put(STATUS, HttpServletResponse.SC_OK);
JsonUtils.render(model, response);
}
}