package com.sissi.pipeline.in.auth.impl;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
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.sasl.AuthorizeCallback;
import javax.security.sasl.Sasl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sissi.commons.Trace;
import com.sissi.context.JIDBuilder;
import com.sissi.context.JIDContext;
import com.sissi.pipeline.in.auth.AuthCallback;
import com.sissi.pipeline.in.auth.SaslServers;
import com.sissi.protocol.iq.auth.Auth;
import com.sissi.protocol.iq.auth.Challenge;
import com.sissi.ucenter.access.AuthAccessor;
/**
* @author kim 2013年11月25日
*/
public class DigestAuthCallback implements AuthCallback {
private final static String mechanism = "DIGEST-MD5";
private final String protocol = "XMPP";
@SuppressWarnings("serial")
private final Map<Class<? extends Callback>, Handler> handlers = new HashMap<Class<? extends Callback>, Handler>() {
{
put(NameCallback.class, new NameCallbackHandler());
put(PasswordCallback.class, new PasswordCallbackHandler());
put(AuthorizeCallback.class, new AuthorizeCallbackHandler());
}
};
@SuppressWarnings("serial")
private final Map<String, String> props = new TreeMap<String, String>() {
{
put(Sasl.QOP, "auth");
}
};
private final Log log = LogFactory.getLog(this.getClass());
private final JIDBuilder jidBuilder;
private final SaslServers saslServers;
private final AuthAccessor authAccessor;
public DigestAuthCallback(JIDBuilder jidBuilder, SaslServers saslServers, AuthAccessor authAccessor) {
super();
this.jidBuilder = jidBuilder;
this.saslServers = saslServers;
this.authAccessor = authAccessor;
}
@Override
public boolean auth(Auth auth, JIDContext context) {
try {
context.write(new Challenge(this.saslServers.push(context, Sasl.createSaslServer(mechanism, this.protocol, context.domain(), this.props, new ServerCallbackHandler(context))).evaluateResponse(new byte[0])));
return true;
} catch (Exception e) {
this.log.error(e.toString());
Trace.trace(this.log, e);
return false;
}
}
public String support() {
return mechanism;
}
private class ServerCallbackHandler implements CallbackHandler {
private final JIDContext context;
private ServerCallbackHandler(JIDContext context) {
super();
this.context = context;
}
public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
Handler handler = DigestAuthCallback.this.handlers.get(callback.getClass());
if (handler != null) {
handler.handler(this.context, callback);
}
}
}
}
private interface Handler {
public void handler(JIDContext context, Callback callback);
}
private class NameCallbackHandler implements Handler {
@Override
public void handler(JIDContext context, Callback callback) {
context.jid(DigestAuthCallback.this.jidBuilder.build(NameCallback.class.cast(callback).getDefaultName(), null));
}
}
private class PasswordCallbackHandler implements Handler {
@Override
public void handler(JIDContext context, Callback callback) {
String pass = DigestAuthCallback.this.authAccessor.access(context.jid().user(), null);
PasswordCallback.class.cast(callback).setPassword(pass != null ? pass.toCharArray() : new char[0]);
}
}
private class AuthorizeCallbackHandler implements Handler {
@Override
public void handler(JIDContext context, Callback callback) {
AuthorizeCallback.class.cast(callback).setAuthorized(true);
}
}
}