/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ws.extensions.security;
//$Id: SendUsernameOperation.java 12505 2010-06-18 13:39:22Z darran.lofthouse@jboss.com $
import java.security.MessageDigest;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import org.jboss.logging.Logger;
import org.jboss.security.Base64Encoder;
import org.jboss.ws.extensions.security.auth.callback.UsernameTokenCallback;
import org.jboss.ws.extensions.security.auth.callback.UsernameTokenCallbackHandler;
import org.jboss.ws.extensions.security.element.SecurityHeader;
import org.jboss.ws.extensions.security.element.UsernameToken;
import org.jboss.xb.binding.SimpleTypeBindings;
import org.w3c.dom.Document;
public class SendUsernameOperation implements EncodingOperation
{
private static Logger log = Logger.getLogger(SendUsernameOperation.class);
private SecurityHeader header;
private SecurityStore store;
public SendUsernameOperation(SecurityHeader header, SecurityStore store)
{
this.header = header;
this.store = store;
}
public void process(Document message, List<Target> targets, String username, String credential, String algorithm, boolean digest, boolean useNonce, boolean useTimestamp) throws WSSecurityException
{
String created = useTimestamp ? getCurrentTimestampAsString() : null;
String nonce = useNonce ? store.getNonceGenerator().generateNonce() : null;
String password = digest ? createPasswordDigest(nonce, created, credential) : credential;
header.addToken(new UsernameToken(username, password, message, digest, nonce, created));
}
private static String getCurrentTimestampAsString()
{
Calendar timestamp = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
return SimpleTypeBindings.marshalDateTime(timestamp);
}
/**
* Calculate the password digest using a MessageDigest and the UsernameTokenCallback/CallbackHandler
*/
@SuppressWarnings("unchecked")
public static String createPasswordDigest(String nonce, String created, String password)
{
String passwordHash = null;
try
{
// convert password to byte data
byte[] passBytes = password.getBytes("UTF-8");
// prepare the username token digest callback
UsernameTokenCallback callback = new UsernameTokenCallback();
Map options = new HashMap();
callback.init(options);
// add the username token callback handler to provide the parameters
CallbackHandler handler = new UsernameTokenCallbackHandler(nonce, created);
handler.handle((Callback[])options.get("callbacks"));
// calculate the hash and apply the encoding.
MessageDigest md = MessageDigest.getInstance("SHA");
callback.preDigest(md);
md.update(passBytes);
callback.postDigest(md);
byte[] hash = md.digest();
passwordHash = Base64Encoder.encode(hash);
}
catch(Exception e)
{
log.error("Password hash calculation failed ", e);
}
return passwordHash;
}
}