/** * 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); } } }