/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.cas.services.web;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.services.RegisteredService;
import org.jasig.cas.services.ServicesManager;
import org.jasig.cas.web.support.ArgumentExtractor;
import org.jasig.cas.web.support.WebUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.theme.AbstractThemeResolver;
/**
* ThemeResolver to determine the theme for CAS based on the service provided and the current
* browser user agent. The theme resolver will extract the service parameter from the Request object
* and attempt to match the URL provided to a Service Id. If the service is found, the theme
* associated with it will be used. If not, these is associated with the service or the service was
* not found, a default theme will be used.
*
* <p>Once this service theme name is resolved, this implementation will look in its overrides map
* to determine if an alternate theme name is configured for the current user agent. This class is
* designed to allow us to define alternate themes for mobile devices on a per-service basis.
*
*/
public class ConfigurableUserAgentOverrideThemeResolver extends AbstractThemeResolver {
/** The ServiceRegistry to look up the service. */
private ServicesManager servicesManager;
private List<ArgumentExtractor> argumentExtractors;
private Map<String, Map<Pattern, String>> overrides;
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.ThemeResolver#resolveThemeName(javax.servlet.http.HttpServletRequest)
*/
public String resolveThemeName(HttpServletRequest request) {
// get the theme name indicated by the service
String themeName = resolveServiceThemeName(request);
/*
* If the overrides map contains overrides for this theme name, iterate
* through the mapped user agent regexes for this theme name. If we
* find a matching regex, set the theme name to the one mapped to that
* regex.
*/
if (overrides.containsKey(themeName)) {
// retrieve the user agent string from the request
String userAgent = request.getHeader("User-Agent");
for (Entry<Pattern, String> entry : overrides.get(themeName).entrySet()) {
if (entry.getKey().matcher(userAgent).matches()) {
return entry.getValue();
}
}
}
// if no override was found for the current theme and user agent,
// return the default theme for this service
return themeName;
}
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.ThemeResolver#setThemeName(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
*/
public void setThemeName(
HttpServletRequest request, HttpServletResponse response, String themeName) {
// nothing to do here
}
/**
* Resolve the theme for the service. This method's logic is taken from ServiceThemeResolver.
*
* @param request
* @return configured theme for this service
*/
protected String resolveServiceThemeName(HttpServletRequest request) {
if (this.servicesManager == null) {
return getDefaultThemeName();
}
final Service service = WebUtils.getService(this.argumentExtractors, request);
final RegisteredService rService = this.servicesManager.findServiceBy(service);
return service != null && rService != null && StringUtils.hasText(rService.getTheme())
? rService.getTheme()
: getDefaultThemeName();
}
public void setServicesManager(final ServicesManager servicesManager) {
this.servicesManager = servicesManager;
}
public void setArgumentExtractors(final List<ArgumentExtractor> argumentExtractors) {
this.argumentExtractors = argumentExtractors;
}
/**
* Set the map of theme name overrides. This map is of the format { service theme name -> { user
* agent regular expression -> override theme name } }
*
* @param overrides
*/
public void setOverrides(Map<String, Map<String, String>> overrides) {
// initialize the overrides variable to an empty map
this.overrides = new HashMap<String, Map<Pattern, String>>();
// convert the provided map's regular expressions to Pattern objects
for (Entry<String, Map<String, String>> themeMapping : overrides.entrySet()) {
Map<Pattern, String> mappings = new LinkedHashMap<Pattern, String>();
for (Entry<String, String> browserMapping : themeMapping.getValue().entrySet()) {
Pattern p = Pattern.compile(browserMapping.getKey());
mappings.put(p, browserMapping.getValue());
}
this.overrides.put(themeMapping.getKey(), mappings);
}
}
}