001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * bstefanescu 011 */ 012package org.nuxeo.runtime.api.login; 013 014import java.io.IOException; 015import java.security.Principal; 016import java.util.Map; 017 018import javax.security.auth.Subject; 019import javax.security.auth.callback.Callback; 020import javax.security.auth.callback.CallbackHandler; 021import javax.security.auth.callback.NameCallback; 022import javax.security.auth.callback.PasswordCallback; 023import javax.security.auth.callback.UnsupportedCallbackException; 024import javax.security.auth.login.LoginException; 025import javax.security.auth.spi.LoginModule; 026 027import org.nuxeo.runtime.api.Framework; 028 029/** 030 * A login module that will use the current registered authenticator to validate a given username / password pair. 031 * 032 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 033 */ 034public class AuthenticationLoginModule implements LoginModule { 035 036 protected Subject subject; 037 038 protected CallbackHandler callbackHandler; 039 040 @SuppressWarnings("rawtypes") 041 protected Map sharedState; 042 043 protected Principal principal; 044 045 public Principal authenticate(String[] login) { 046 return Framework.getService(Authenticator.class).authenticate(login[0], login[1]); 047 } 048 049 @Override 050 public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, 051 Map<String, ?> options) { 052 this.subject = subject; 053 this.callbackHandler = callbackHandler; 054 this.sharedState = sharedState; 055 } 056 057 protected String[] retrieveLogin() throws LoginException { 058 PasswordCallback pc = new PasswordCallback("Password: ", false); 059 NameCallback nc = new NameCallback("Username: ", "guest"); 060 Callback[] callbacks = { nc, pc }; 061 try { 062 String[] login = new String[2]; 063 callbackHandler.handle(callbacks); 064 login[0] = nc.getName(); 065 char[] tmpPassword = pc.getPassword(); 066 if (tmpPassword != null) { 067 login[1] = new String(tmpPassword); 068 } 069 pc.clearPassword(); 070 return login; 071 } catch (IOException ioe) { 072 throw new LoginException(ioe.toString()); 073 } catch (UnsupportedCallbackException uce) { 074 throw new LoginException("Error: " + uce.getCallback().toString() 075 + " not available to gather authentication information " + "from the user"); 076 } 077 } 078 079 @SuppressWarnings("unchecked") 080 @Override 081 public boolean login() throws LoginException { 082 String[] login = retrieveLogin(); 083 try { 084 principal = authenticate(login); 085 } catch (RuntimeException e) { 086 LoginException ee = new LoginException("Authentication failed for " + login[0]); 087 ee.initCause(e); 088 throw ee; 089 } 090 if (principal == null) { 091 throw new LoginException("Authentication failed for " + login[0]); 092 } 093 sharedState.put("javax.security.auth.login.name", principal); 094 // sharedState.put("javax.security.auth.login.password", login[1]); 095 return true; 096 } 097 098 @Override 099 public boolean abort() throws LoginException { 100 return true; 101 } 102 103 @Override 104 public boolean commit() throws LoginException { 105 if (principal != null) { 106 subject.getPrincipals().add(principal); 107 return true; 108 } else { 109 return false; 110 } 111 } 112 113 @Override 114 public boolean logout() throws LoginException { 115 if (principal != null) { 116 subject.getPrincipals().remove(principal); 117 } 118 return true; 119 } 120 121}