001/*
002 * (C) Copyright 2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 * Contributors:
014 *     Nuxeo - initial API and implementation
015 */
016
017package org.nuxeo.ecm.platform.shibboleth.auth;
018
019import java.io.IOException;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import javax.servlet.http.HttpServletRequest;
025import javax.servlet.http.HttpServletResponse;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.ecm.core.api.DocumentModel;
031import org.nuxeo.ecm.directory.DirectoryException;
032import org.nuxeo.ecm.directory.Session;
033import org.nuxeo.ecm.directory.api.DirectoryService;
034import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo;
035import org.nuxeo.ecm.platform.shibboleth.service.ShibbolethAuthenticationService;
036import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin;
037import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPluginLogoutExtension;
038import org.nuxeo.ecm.platform.usermanager.UserManager;
039import org.nuxeo.runtime.api.Framework;
040import org.nuxeo.usermapper.extension.UserMapper;
041import org.nuxeo.usermapper.service.UserMapperService;
042
043public class ShibbolethAuthenticationPlugin implements NuxeoAuthenticationPlugin,
044        NuxeoAuthenticationPluginLogoutExtension {
045
046    private static final Log log = LogFactory.getLog(ShibbolethAuthenticationPlugin.class);
047
048    public static final String EXTERNAL_MAPPER_PARAM = "mapper";
049
050    public static final String DEFAULT_EXTERNAL_MAPPER = "shibboleth";
051
052    protected UserMapper externalMapper = null;
053
054    protected ShibbolethAuthenticationService getService() {
055        return Framework.getService(ShibbolethAuthenticationService.class);
056    }
057
058    @Override
059    public List<String> getUnAuthenticatedURLPrefix() {
060        return null;
061    }
062
063    @Override
064    public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) {
065        if (getService() == null) {
066            return false;
067        }
068        String loginURL = getService().getLoginURL(httpRequest);
069        if (loginURL == null) {
070            log.error("Unable to handle Shibboleth login, no loginURL registered");
071            return false;
072        }
073        try {
074            httpResponse.sendRedirect(loginURL);
075        } catch (IOException e) {
076            String errorMessage = String.format("Unable to handle Shibboleth login on %s", loginURL);
077            log.error(errorMessage, e);
078            return false;
079        }
080        return true;
081    }
082
083    @Override
084    public Boolean handleLogout(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
085        if (getService() == null) {
086            return false;
087        }
088        String logoutURL = getService().getLogoutURL(httpRequest);
089        if (logoutURL == null) {
090            return false;
091        }
092        try {
093            httpResponse.sendRedirect(logoutURL);
094        } catch (IOException e) {
095            log.error("Unable to handle Shibboleth logout", e);
096            return false;
097        }
098        return true;
099    }
100
101    @Override
102    public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest,
103            HttpServletResponse httpResponse) {
104        if (getService() == null) {
105            return null;
106        }
107
108        String userId = getService().getUserID(httpRequest);
109        if (userId == null || StringUtils.EMPTY.equals(userId)) {
110            return null;
111        } else {
112            UserMapperService ums = Framework.getService(UserMapperService.class);
113            if (ums != null) {
114                if (ums.getAvailableMappings().contains(DEFAULT_EXTERNAL_MAPPER)) {
115                    externalMapper = ums.getMapper(DEFAULT_EXTERNAL_MAPPER);
116                }
117            }
118        }
119        UserManager userManager = Framework.getService(UserManager.class);
120        Map<String, Object> fieldMap = getService().getUserMetadata(userManager.getUserIdField(), httpRequest);
121
122        if (externalMapper != null) {
123            Map<String, Object> nativeObject = new HashMap<String, Object>();
124            nativeObject.putAll(fieldMap);
125            nativeObject.put("userId", userId);
126            externalMapper.getOrCreateAndUpdateNuxeoPrincipal(nativeObject);
127        } else {
128            try (Session userDir = Framework.getService(DirectoryService.class).open(userManager.getUserDirectoryName())) {
129                DocumentModel entry = userDir.getEntry(userId);
130                if (entry == null) {
131                    userDir.createEntry(fieldMap);
132                } else {
133                    entry.getDataModel(userManager.getUserSchemaName()).setMap(fieldMap);
134                    userDir.updateEntry(entry);
135                }
136            } catch (DirectoryException e) {
137                log.error("Failed to get or create user entry", e);
138            }
139        }
140
141        return new UserIdentificationInfo(userId, userId);
142    }
143
144    @Override
145    public Boolean needLoginPrompt(HttpServletRequest httpRequest) {
146        return true;
147    }
148
149    @Override
150    public void initPlugin(Map<String, String> parameters) {
151    }
152
153}