/*
* File: XmlUsersFileModule.java
*
* Copyright 2009 Muradora
*
* Licensed 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.fcrepo.server.jaas.auth.module;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.apache.log4j.Logger;
import org.fcrepo.server.jaas.auth.UserPrincipal;
import org.fcrepo.server.jaas.util.DataUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class XmlUsersFileModule
implements LoginModule {
private static final Logger log =
Logger.getLogger(XmlUsersFileModule.class);
private Subject subject = null;
private CallbackHandler handler = null;
// private Map<String, ?> sharedState = null;
private Map<String, ?> options = null;
private String fedoraHome = null;
private String username = null;
private UserPrincipal principal = null;
private Map<String, Set<String>> attributes = null;
private boolean debug = false;
private boolean successLogin = false;
public void initialize(Subject subject,
CallbackHandler handler,
Map<String, ?> sharedState,
Map<String, ?> options) {
this.subject = subject;
this.handler = handler;
// this.sharedState = sharedState;
this.options = options;
String debugOption = (String) this.options.get("debug");
if (debugOption != null && "true".equalsIgnoreCase(debugOption)) {
debug = true;
}
fedoraHome = System.getenv("FEDORA_HOME");
if (fedoraHome == null || "".equals(fedoraHome)) {
log.error("FEDORA_HOME environment variable not set");
} else {
if (log.isDebugEnabled()) {
log.debug("using FEDORA_HOME: " + fedoraHome);
}
}
attributes = new HashMap<String, Set<String>>();
if (debug) {
log.debug("login module initialised: " + this.getClass().getName());
}
}
public boolean login() throws LoginException {
if (debug) {
log.debug(this.getClass().getName() + " login called.");
}
if (fedoraHome == null || "".equals(fedoraHome.trim())) {
log.error("FEDORA_HOME environment variable not set");
return false;
}
// The only 2 callback types that are supported.
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("username");
callbacks[1] = new PasswordCallback("password", false);
String password = null;
try {
// sets the username and password from the callback handler
handler.handle(callbacks);
username = ((NameCallback) callbacks[0]).getName();
char[] passwordCharArray =
((PasswordCallback) callbacks[1]).getPassword();
password = new String(passwordCharArray);
} catch (IOException ioe) {
ioe.printStackTrace();
throw new LoginException("IOException occured: " + ioe.getMessage());
} catch (UnsupportedCallbackException ucbe) {
ucbe.printStackTrace();
throw new LoginException("UnsupportedCallbackException encountered: "
+ ucbe.getMessage());
}
successLogin = authenticate(username, password);
return successLogin;
}
public boolean commit() throws LoginException {
if (!successLogin) {
return false;
}
try {
subject.getPrincipals().add(principal);
subject.getPublicCredentials().add(attributes);
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
return true;
}
public boolean abort() throws LoginException {
try {
clear();
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
return true;
}
public boolean logout() throws LoginException {
try {
clear();
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
return true;
}
private void clear() {
subject.getPrincipals().clear();
subject.getPublicCredentials().clear();
subject.getPrivateCredentials().clear();
principal = null;
username = null;
}
private boolean authenticate(String username, String password) {
String xmlUsersFile = fedoraHome + "/server/config/fedora-users.xml";
File file = new File(xmlUsersFile);
if (!file.exists()) {
log.error("XmlUsersFile not found: " + file.getAbsolutePath());
return false;
}
Document doc = null;
try {
doc = DataUtils.getDocumentFromFile(new File(xmlUsersFile));
// go through each user
NodeList userList = doc.getElementsByTagName("user");
for (int x = 0; x < userList.getLength(); x++) {
Element user = (Element) userList.item(x);
String a_username = user.getAttribute("name");
String a_password = user.getAttribute("password");
if (!a_username.equals(username)
|| !a_password.equals(password)) {
continue;
}
principal = new UserPrincipal(username);
// for a matched user, go through each attribute
NodeList attributeList = user.getElementsByTagName("attribute");
for (int y = 0; y < attributeList.getLength(); y++) {
Element attribute = (Element) attributeList.item(y);
String name = attribute.getAttribute("name");
// go through each value
NodeList valueList =
attribute.getElementsByTagName("value");
for (int z = 0; z < valueList.getLength(); z++) {
Element value = (Element) valueList.item(z);
String v = value.getFirstChild().getNodeValue();
Set<String> values = attributes.get(name);
if (values == null) {
values = new HashSet<String>();
attributes.put(name, values);
}
values.add(v);
}
}
return true;
}
} catch (Exception e) {
log.error(e.getMessage());
}
return false;
}
}