/**
* Licensed to the Sakai Foundation (SF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The SF 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.sakaiproject.provider.user;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.component.api.ComponentManager;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.hybrid.util.NakamuraAuthenticationHelper;
import org.sakaiproject.hybrid.util.NakamuraAuthenticationHelper.AuthInfo;
import org.sakaiproject.hybrid.util.XSakaiToken;
import org.sakaiproject.thread_local.api.ThreadLocalManager;
import org.sakaiproject.user.api.UserDirectoryProvider;
import org.sakaiproject.user.api.UserEdit;
/**
* Authenticates users who have already been authenticated to a Nakamura
* instance.
*/
public class NakamuraUserDirectoryProvider implements UserDirectoryProvider {
private static final Log LOG = LogFactory
.getLog(NakamuraUserDirectoryProvider.class);
/**
* Key in the ThreadLocalManager for access to the current
* {@link HttpServletRequest} object.
*/
static final String CURRENT_HTTP_REQUEST = "org.sakaiproject.util.RequestFilter.http_request";
/**
* All sakai.properties settings will be prefixed with this string.
*/
public static final String CONFIG_PREFIX = "org.sakaiproject.provider.user.NakamuraUserDirectoryProvider";
/**
* The principal that will be used when connecting to Nakamura REST
* end-point. Must have permissions to read /var/cluster/user.cookie.json.
*
* @see XSakaiToken#createToken(String, String)
*/
public static final String CONFIG_PRINCIPAL = CONFIG_PREFIX + ".principal";
/**
* The hostname we will use to lookup the sharedSecret for access to
* validateUrl.
*
* @see XSakaiToken#createToken(String, String)
*/
public static final String CONFIG_HOST_NAME = CONFIG_PREFIX + ".hostname";
/**
* The Nakamura REST end-point we will use to validate the cookie
*/
public static final String CONFIG_VALIDATE_URL = CONFIG_PREFIX
+ ".validateUrl";
/**
* The Nakamura RESTful service to validate authenticated users. A good
* default for common hybrid implementations is supplied.
*
* @see #CONFIG_VALIDATE_URL
*/
protected String validateUrl = "http://localhost/var/cluster/user.cookie.json?c=";
/**
* The nakamura user that has permissions to GET
* /var/cluster/user.cookie.json. A good default for common hybrid
* implementations is supplied.
*
* @see XSakaiToken#createToken(String, String)
* @see #CONFIG_PRINCIPAL
*/
protected String principal = "admin";
/**
* The hostname we will use to lookup the sharedSecret for access to
* validateUrl. A good default for common hybrid implementations is
* supplied.
*
* @see XSakaiToken#createToken(String, String)
* @see #CONFIG_HOST_NAME
*/
protected String hostname = "localhost";
// dependencies
ComponentManager componentManager; // injected
ThreadLocalManager threadLocalManager; // injected
ServerConfigurationService serverConfigurationService; // injected
NakamuraAuthenticationHelper nakamuraAuthenticationHelper;
/**
* @see org.sakaiproject.user.api.UserDirectoryProvider#authenticateUser(java.lang.String,
* org.sakaiproject.user.api.UserEdit, java.lang.String)
*/
public boolean authenticateUser(String eid, UserEdit edit, String password) {
if (LOG.isDebugEnabled()) {
LOG.debug("authenticateUser(String " + eid + ", UserEdit " + edit
+ ", String password)");
}
if (eid == null || "null".equalsIgnoreCase(eid) || "".equals(eid)) {
// maybe should throw exception instead?
// since I assume I am in a chain, I will be quiet about it
LOG.debug("eid == null");
return false;
}
final AuthInfo authInfo = nakamuraAuthenticationHelper
.getPrincipalLoggedIntoNakamura(getHttpServletRequest());
if (authInfo != null) {
if (eid.equalsIgnoreCase(authInfo.getPrincipal())) {
edit.setEid(authInfo.getPrincipal());
edit.setFirstName(authInfo.getFirstName());
edit.setLastName(authInfo.getLastName());
edit.setEmail(authInfo.getEmailAddress());
return true;
}
}
return false;
}
/**
* @see org.sakaiproject.user.api.UserDirectoryProvider#authenticateWithProviderFirst(java.lang.String)
*/
public boolean authenticateWithProviderFirst(String eid) {
if (LOG.isDebugEnabled()) {
LOG.debug("authenticateWithProviderFirst(String " + eid + ")");
}
// What is the best default?
return false;
}
/**
* @see org.sakaiproject.user.api.UserDirectoryProvider#findUserByEmail(org.sakaiproject.user.api.UserEdit,
* java.lang.String)
*/
public boolean findUserByEmail(UserEdit edit, String email) {
if (LOG.isDebugEnabled()) {
LOG.debug("findUserByEmail(UserEdit " + edit + ", String " + email
+ ")");
}
if (email == null) {
LOG.debug("String email == null");
return false;
}
final AuthInfo authInfo = nakamuraAuthenticationHelper
.getPrincipalLoggedIntoNakamura(getHttpServletRequest());
if (authInfo != null) {
if (email.equalsIgnoreCase(authInfo.getEmailAddress())) {
edit.setEid(authInfo.getPrincipal());
edit.setFirstName(authInfo.getFirstName());
edit.setLastName(authInfo.getLastName());
edit.setEmail(authInfo.getEmailAddress());
return true;
}
}
return false;
}
/**
* @see org.sakaiproject.user.api.UserDirectoryProvider#getUser(org.sakaiproject.user.api.UserEdit)
*/
public boolean getUser(UserEdit edit) {
if (LOG.isDebugEnabled()) {
LOG.debug("getUser(UserEdit " + edit + ")");
}
/*
* For some crazy reason, the not-null String "null" can be passed in
* edit.getEid(). Very odd behavior indeed.
*/
if (edit != null) {
final String eid = edit.getEid();
if (eid != null && !"null".equalsIgnoreCase(eid)) {
return authenticateUser(edit.getEid(), edit, null);
}
}
LOG.debug("UserEdit edit == null || null eid");
return false;
}
/**
* @see org.sakaiproject.user.api.UserDirectoryProvider#getUsers(java.util.Collection)
*/
public void getUsers(Collection<UserEdit> users) {
if (LOG.isDebugEnabled()) {
LOG.debug("getUsers(Collection<UserEdit> " + users + ")");
}
LOG.warn("Method is not currently supported");
// nothing to do here...
return;
}
/**
* Gets a reference to {@link HttpServletRequest} via ThreadLocalManager.
*
* @return
*/
protected HttpServletRequest getHttpServletRequest() {
LOG.debug("getHttpServletRequest()");
final HttpServletRequest request = (HttpServletRequest) threadLocalManager
.get(CURRENT_HTTP_REQUEST);
if (request == null) {
throw new IllegalStateException("HttpServletRequest == null");
}
return request;
}
/**
* Initialize class.
*/
public void init() {
LOG.debug("init()");
if (componentManager == null) { // may be in a test
componentManager = org.sakaiproject.component.cover.ComponentManager
.getInstance();
}
validateUrl = serverConfigurationService.getString(CONFIG_VALIDATE_URL,
validateUrl);
principal = serverConfigurationService.getString(CONFIG_PRINCIPAL,
principal);
hostname = serverConfigurationService.getString(CONFIG_HOST_NAME,
hostname);
if (nakamuraAuthenticationHelper == null) {
nakamuraAuthenticationHelper = new NakamuraAuthenticationHelper(
componentManager, validateUrl, principal, hostname);
}
}
/**
* @param threadLocalManager
* the threadLocalManager to inject
*/
public void setThreadLocalManager(ThreadLocalManager threadLocalManager) {
LOG.debug("setThreadLocalManager(ThreadLocalManager threadLocalManager)");
this.threadLocalManager = threadLocalManager;
}
/**
* @param componentManager
* the componentManager to set
*/
public void setComponentManager(ComponentManager componentManager) {
LOG.debug("setComponentManager(ComponentManager componentManager)");
this.componentManager = componentManager;
}
/**
* @param serverConfigurationService
* the serverConfigurationService to set
*/
public void setServerConfigurationService(
ServerConfigurationService serverConfigurationService) {
LOG.debug("setServerConfigurationService(ServerConfigurationService serverConfigurationService)");
this.serverConfigurationService = serverConfigurationService;
}
}