/**
* 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.portlet.container.services;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.portlet.PortletRequest;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.Validate;
import org.apache.pluto.container.PortletContainerException;
import org.apache.pluto.container.PortletWindow;
import org.apache.pluto.container.UserInfoService;
import org.apache.pluto.container.om.portlet.PortletApplicationDefinition;
import org.apache.pluto.container.om.portlet.UserAttribute;
import org.apereo.portal.portlet.om.IPortletDefinition;
import org.apereo.portal.portlet.om.IPortletEntity;
import org.apereo.portal.portlet.om.IPortletWindow;
import org.apereo.portal.portlet.registry.IPortletDefinitionRegistry;
import org.apereo.portal.portlet.registry.IPortletEntityRegistry;
import org.apereo.portal.portlet.registry.IPortletWindowRegistry;
import org.apereo.portal.security.IOpaqueCredentials;
import org.apereo.portal.security.IPerson;
import org.apereo.portal.security.ISecurityContext;
import org.apereo.portal.security.IStringEncryptionService;
import org.apereo.portal.security.provider.NotSoOpaqueCredentials;
import org.apereo.portal.url.IPortalRequestUtils;
import org.apereo.portal.user.IUserInstance;
import org.apereo.portal.user.IUserInstanceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class CachedPasswordUserInfoService implements UserInfoService {
private IUserInstanceManager userInstanceManager;
private IPortletWindowRegistry portletWindowRegistry;
private IPortletEntityRegistry portletEntityRegistry;
private IPortletDefinitionRegistry portletDefinitionRegistry;
private IPortalRequestUtils portalRequestUtils;
private IStringEncryptionService stringEncryptionService;
protected final Logger log = LoggerFactory.getLogger(getClass());
/** @return the portalRequestUtils */
public IPortalRequestUtils getPortalRequestUtils() {
return portalRequestUtils;
}
/** @param portalRequestUtils the portalRequestUtils to set */
@Autowired(required = true)
public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) {
Validate.notNull(portalRequestUtils);
this.portalRequestUtils = portalRequestUtils;
}
/** The default name of the preferences attribute used to pass the PT to the portlet. */
private String passwordKey = "password";
/** @return the UserInstanceManager */
public IUserInstanceManager getUserInstanceManager() {
return userInstanceManager;
}
/** @param userInstanceManager the UserInstanceManager */
@Autowired(required = true)
public void setUserInstanceManager(IUserInstanceManager userInstanceManager) {
this.userInstanceManager = userInstanceManager;
}
/** @return the portletEntityRegistry */
public IPortletEntityRegistry getPortletEntityRegistry() {
return this.portletEntityRegistry;
}
/** @param portletEntityRegistry the portletEntityRegistry to set */
@Autowired(required = true)
public void setPortletEntityRegistry(IPortletEntityRegistry portletEntityRegistry) {
this.portletEntityRegistry = portletEntityRegistry;
}
/** @return the portletWindowRegistry */
public IPortletWindowRegistry getPortletWindowRegistry() {
return this.portletWindowRegistry;
}
/** @param portletWindowRegistry the portletWindowRegistry to set */
@Autowired(required = true)
public void setPortletWindowRegistry(IPortletWindowRegistry portletWindowRegistry) {
this.portletWindowRegistry = portletWindowRegistry;
}
/** @return the portletDefinitionRegistry */
public IPortletDefinitionRegistry getPortletDefinitionRegistry() {
return this.portletDefinitionRegistry;
}
/** @param portletDefinitionRegistry the portletDefinitionRegistry to set */
@Autowired(required = true)
public void setPortletDefinitionRegistry(IPortletDefinitionRegistry portletDefinitionRegistry) {
this.portletDefinitionRegistry = portletDefinitionRegistry;
}
@Autowired
public void setStringEncryptionService(IStringEncryptionService stringEncryptionService) {
this.stringEncryptionService = stringEncryptionService;
}
private boolean decryptPassword = false;
/**
* Set whether the password should be decrypted before adding it to the user info map.
*
* @param decryptPassword
*/
public void setDecryptPassword(boolean decryptPassword) {
this.decryptPassword = decryptPassword;
}
/** @return name of the key to save the password under */
public String getPasswordKey() {
return passwordKey;
}
/** @param passwordKey name of the key to save the password under */
public void setPasswordKey(String passwordKey) {
this.passwordKey = passwordKey;
}
/*
* (non-Javadoc)
* @see org.apache.pluto.container.UserInfoService#getUserInfo(javax.portlet.PortletRequest, org.apache.pluto.container.PortletWindow)
*/
@Override
public Map<String, String> getUserInfo(PortletRequest request, PortletWindow portletWindow)
throws PortletContainerException {
Map<String, String> userInfo = new HashMap<String, String>();
// check to see if a password is expected by this portlet
if (isPasswordRequested(request, portletWindow)) {
log.debug(
"Portlet named {} wants a password",
portletWindow.getPortletDefinition().getPortletName());
final HttpServletRequest httpServletRequest =
this.portalRequestUtils.getPortletHttpRequest(request);
final IUserInstance userInstance =
userInstanceManager.getUserInstance(httpServletRequest);
final IPerson person = userInstance.getPerson();
final ISecurityContext context = person.getSecurityContext();
// if it is, attempt to request a password
String password = getPassword(context);
log.debug(password != null ? "Have a non-null password" : "password was null");
if (this.decryptPassword && password != null) {
log.debug("Attempting to decrypt password");
password = stringEncryptionService.decrypt(password);
log.debug(
"Password decryption complete, password is length {}",
password != null ? password.length() : "is null");
}
if (password != null) {
userInfo.put(this.passwordKey, password);
log.debug(
"Found password with length {} for portlet name {}",
password.length() != 0 ? "non-zero" : 0,
portletWindow.getPortletDefinition().getPortletName());
}
}
return userInfo;
}
/**
* Determine whether the portlet has expects a password as one of the user attributes.
*
* @param request portlet request
* @param plutoPortletWindow portlet window
* @return <code>true</code> if a password is expected, <code>false</code> otherwise
* @throws PortletContainerException if expeced attributes cannot be determined
*/
public boolean isPasswordRequested(PortletRequest request, PortletWindow plutoPortletWindow)
throws PortletContainerException {
// get the list of requested user attributes
final HttpServletRequest httpServletRequest =
this.portalRequestUtils.getPortletHttpRequest(request);
final IPortletWindow portletWindow =
this.portletWindowRegistry.convertPortletWindow(
httpServletRequest, plutoPortletWindow);
final IPortletEntity portletEntity = portletWindow.getPortletEntity();
final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition();
final PortletApplicationDefinition portletApplicationDescriptor =
this.portletDefinitionRegistry.getParentPortletApplicationDescriptor(
portletDefinition.getPortletDefinitionId());
// check to see if the password key is one of the requested user attributes
List<? extends UserAttribute> requestedUserAttributes =
portletApplicationDescriptor.getUserAttributes();
for (final UserAttribute userAttributeDD : requestedUserAttributes) {
final String attributeName = userAttributeDD.getName();
if (attributeName.equals(this.passwordKey)) return true;
}
// if the password key wasn't found in the list of requested attributes
return false;
}
/**
* Retrieves the users password by iterating over the user's security contexts and returning the
* first available cached password.
*
* @param baseContext The security context to start looking for a password from.
* @return the users password
*/
private String getPassword(ISecurityContext baseContext) {
String password = null;
IOpaqueCredentials oc = baseContext.getOpaqueCredentials();
if (oc instanceof NotSoOpaqueCredentials) {
NotSoOpaqueCredentials nsoc = (NotSoOpaqueCredentials) oc;
password = nsoc.getCredentials();
}
// If still no password, loop through subcontexts to find cached credentials
Enumeration en = baseContext.getSubContexts();
while (password == null && en.hasMoreElements()) {
ISecurityContext subContext = (ISecurityContext) en.nextElement();
password = this.getPassword(subContext);
}
return password;
}
}