001/* 002 * Copyright 2016 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.parameters.Parameters; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.cocoon.environment.ObjectModelHelper; 027import org.apache.cocoon.environment.Redirector; 028import org.apache.cocoon.environment.Request; 029import org.apache.cocoon.environment.SourceResolver; 030import org.apache.commons.collections.CollectionUtils; 031 032import org.ametys.core.authentication.AuthenticateAction; 033import org.ametys.core.authentication.CredentialProvider; 034import org.ametys.core.user.UserIdentity; 035import org.ametys.core.user.population.UserPopulationDAO; 036import org.ametys.core.util.StringUtils; 037import org.ametys.runtime.authentication.AccessDeniedException; 038import org.ametys.runtime.config.Config; 039import org.ametys.web.repository.site.SiteManager; 040 041/** 042 * Special authentication process for web context and aware of front-offices. 043 */ 044public class WebAuthenticateAction extends AuthenticateAction 045{ 046 /** The request attribute to set front office user identity */ 047 public static final String REQUEST_ATTRIBUTE_FRONTOFFICE_USERIDENTITY = "Web:FrontOffice:UserIdentity"; 048 /** The request attribute to set front office credential provider id */ 049 public static final String REQUEST_ATTRIBUTE_FRONTOFFICE_CREDENTIALPROVIDER_ID = "Web:FrontOffice:CredentialProviderId"; 050 /** The request attribute set to "true" when the request came from the front and was IP checked */ 051 public static final String REQUEST_ATTRIBUTE_FRONTOFFICE_REQUEST = "Web:FrontOffice:Request"; 052 053 private static UserPopulationDAO _staticUserPopulationDAO; 054 055 private SiteManager _siteManager; 056 057 @Override 058 public void service(ServiceManager smanager) throws ServiceException 059 { 060 super.service(smanager); 061 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 062 if (_staticUserPopulationDAO == null) 063 { 064 _staticUserPopulationDAO = (UserPopulationDAO) smanager.lookup(UserPopulationDAO.ROLE); 065 } 066 } 067 068 @Override 069 protected List<String> _getContexts(Request request, Parameters parameters) 070 { 071 // We return all the populations linked to at least one site 072 List<String> contexts = new ArrayList<>(); 073 074 // Retrieve the sites to build the contexts to search on 075 Collection<String> siteNames = _siteManager.getSiteNames(); 076 077 for (String context : super._getContexts(request, parameters)) 078 { 079 for (String siteName : siteNames) 080 { 081 String siteContext = context + "/" + siteName; 082 contexts.add(siteContext); 083 } 084 } 085 086 return contexts; 087 } 088 089 @Override 090 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 091 { 092 Request request = ObjectModelHelper.getRequest(objectModel); 093 if ("true".equals(request.getHeader("X-Ametys-FO"))) 094 { 095 // The request seems to come from an FO, verify the IP address 096 String conf = Config.getInstance().getValue("org.ametys.web.front.ip"); 097 Collection<String> ips = StringUtils.stringToCollection(conf); 098 099 // The real client IP may have been put in the non-standard "X-Forwarded-For" request header, in case of reverse proxy 100 String xff = request.getHeader("X-Forwarded-For"); 101 Collection<String> remoteIps = StringUtils.stringToCollection(xff); 102 remoteIps.add(request.getRemoteAddr()); 103 104 if (!ips.isEmpty() && !CollectionUtils.containsAny(ips, remoteIps)) 105 { 106 throw new AccessDeniedException("IP '" + org.apache.commons.lang.StringUtils.join(remoteIps, ", ") + "' is not an authorized front-office IP (" + conf + ")"); 107 } 108 109 String login = request.getHeader("X-Ametys-FO-Login"); 110 String populationId = request.getHeader("X-Ametys-FO-Population"); 111 if (org.apache.commons.lang3.StringUtils.isNoneBlank(login, populationId)) 112 { 113 UserIdentity frontUserIdentity = new UserIdentity(login, populationId); 114 request.setAttribute(REQUEST_ATTRIBUTE_FRONTOFFICE_USERIDENTITY, frontUserIdentity); 115 } 116 117 String credentialProvicerId = request.getHeader("X-Ametys-FO-Credential-Provider"); 118 if (org.apache.commons.lang3.StringUtils.isNotBlank(credentialProvicerId)) 119 { 120 request.setAttribute(REQUEST_ATTRIBUTE_FRONTOFFICE_CREDENTIALPROVIDER_ID, credentialProvicerId); 121 } 122 123 request.setAttribute(REQUEST_ATTRIBUTE_AUTHENTICATED, "true"); 124 request.setAttribute(REQUEST_ATTRIBUTE_FRONTOFFICE_REQUEST, "true"); 125 return EMPTY_MAP; 126 } 127 128 request.setAttribute(REQUEST_ATTRIBUTE_FRONTOFFICE_REQUEST, "false"); // A request using the dispatch generator can add anything in the request attributes 129 return super.act(redirector, resolver, objectModel, source, parameters); 130 } 131 132 @Override 133 protected CredentialProvider _getCredentialProviderFromSession(Request request) 134 { 135 return getCredentialProviderFromSession(request); 136 } 137 138 /** 139 * Get the credential provider used for the current connection 140 * @param request The request 141 * @return The credential provider used or null 142 */ 143 public static CredentialProvider getCredentialProviderFromSession(Request request) 144 { 145 String credentialProviderId = (String) request.getAttribute(REQUEST_ATTRIBUTE_FRONTOFFICE_CREDENTIALPROVIDER_ID); 146 if (org.apache.commons.lang3.StringUtils.isNotBlank(credentialProviderId)) 147 { 148 UserIdentity userIdentity = (UserIdentity) request.getAttribute(REQUEST_ATTRIBUTE_FRONTOFFICE_USERIDENTITY); 149 String populationId = userIdentity.getPopulationId(); 150 return _staticUserPopulationDAO.getUserPopulation(populationId) 151 .getCredentialProvider(credentialProviderId); 152 } 153 else 154 { 155 return AuthenticateAction.getCredentialProviderFromSession(request); 156 } 157 } 158}