Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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.apache.hadoop.io.crypto.bee.key.sasl; import java.io.IOException; import java.util.Map; import java.util.TreeMap; import java.util.UUID; 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.RealmCallback; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import org.apache.commons.codec.binary.Hex; import org.apache.hadoop.io.crypto.bee.key.sasl.common.KeyToken; import org.apache.hadoop.io.crypto.bee.key.sasl.common.SaslUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class KeySaslServer { final Logger logger = LoggerFactory.getLogger(getClass()); private UUID uuid; // Each KeySaslServer has a unique ID. Server will send // back this ID to client while INIT private KeyToken keyToken; // One pwdIdentifier may map to multiple UUID (A // password // token maybe use multiple times in a Job) private SaslServer saslSrv; // Each UUID map to a SaslServer SaslUtil.SaslAuthStatus saslAuthStatus; long ttl = 0;// If timestamp > 20 sec, drop this keySaslServer. (20 sec is // enough to exchange auth & data) /** * @return the ttl */ public long getTtl() { return ttl; } public String getTokenUser() { return keyToken.getUser(); } private final Map<String, String> propsServer = new TreeMap<String, String>(); public KeySaslServer(UUID uuid, KeyToken keyToken) throws SaslException { this.uuid = uuid; this.keyToken = keyToken; propsServer.put(Sasl.QOP, "auth-conf,auth-int,auth"); saslSrv = Sasl.createSaslServer("DIGEST-MD5", SaslUtil.KEY_SERVICE, SaslUtil.KEY_REALM, propsServer, new ServerCallbackHandler(this.keyToken)); saslAuthStatus = SaslUtil.SaslAuthStatus.AUTH_PROCESSING; this.ttl = new java.util.Date().getTime() + SaslUtil.SASL_ENTRY_TTL; } public byte[] init() throws SaslException { logger.debug("init server"); return saslSrv.evaluateResponse(new byte[0]); } public byte[] auth(byte[] response) throws SaslException { logger.debug("authenticate server"); // TODO: how about to add a username checking // TODO: drop the exception maybe better in case there are too many error // trying byte[] challenge = saslSrv.evaluateResponse(response); if (saslSrv.isComplete()) { this.saslAuthStatus = SaslUtil.SaslAuthStatus.AUTH_SUCCESS; } return challenge; } /** * @return the uuid */ public UUID getUuid() { return uuid; } /** * @return the saslAuthStatus */ public SaslUtil.SaslAuthStatus getSaslAuthStatus() { return saslAuthStatus; } public byte[] dataProcess(byte[] getData) throws SaslException { if (saslAuthStatus.equals(SaslUtil.SaslAuthStatus.AUTH_SUCCESS)) { byte[] realMsg = saslSrv.unwrap(getData, 0, getData.length); String keyName = new String(realMsg); String tokenUser = keyToken.getUser(); String strKeyHex = "4c7e62f001ae63fd7567f9c9bd5ca1e161396726bea70fe843fec0f771546da7";// Test // Only: // use // keyName // + // username // to // get // real // key byte[] encrypted = saslSrv.wrap(strKeyHex.getBytes(), 0, strKeyHex.length()); return encrypted; } else { logger.warn("Abnormal behavior. The Auth Process is not complete"); return "".getBytes();// not to play me } } public byte[] dataProcess(byte[] dataBytes, boolean bWrap) throws SaslException { logger.debug("doing data process"); if (saslAuthStatus.equals(SaslUtil.SaslAuthStatus.AUTH_SUCCESS)) { if (bWrap) { return saslSrv.wrap(dataBytes, 0, dataBytes.length); } else { return saslSrv.unwrap(dataBytes, 0, dataBytes.length); } } else { logger.warn("Abnormal behavior. The Auth Process is not complete"); return "".getBytes();// not to play me } } } class ServerCallbackHandler implements CallbackHandler { final Logger logger = LoggerFactory.getLogger(getClass()); private KeyToken keyToken; public ServerCallbackHandler(KeyToken keyToken) { this.keyToken = keyToken; } public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback callback : callbacks) { if (callback instanceof RealmCallback) { // do your business } else if (callback instanceof NameCallback) { // do your business } else if (callback instanceof PasswordCallback) { ((PasswordCallback) callback).setPassword(new String(keyToken.getPassword()).toCharArray()); // logger.debug("set password:" + // Hex.encodeHexString(keyToken.getPassword())); } else if (callback instanceof AuthorizeCallback) { // logger.debug("set authorized to true"); AuthorizeCallback authCallback = ((AuthorizeCallback) callback); authCallback.setAuthorized(true); } else { // logger.error(callback.getClass().getName()); throw new UnsupportedCallbackException(callback, "Unrecognized Callback"); } } } }