/* * * 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.qpid.management.common.sasl; import org.apache.harmony.javax.security.auth.callback.Callback; import org.apache.harmony.javax.security.auth.callback.CallbackHandler; import org.apache.harmony.javax.security.auth.callback.NameCallback; import org.apache.harmony.javax.security.auth.callback.PasswordCallback; import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException; import de.measite.smack.Sasl; import org.apache.harmony.javax.security.sasl.SaslClient; import org.apache.harmony.javax.security.sasl.SaslException; import java.io.IOException; import java.io.UnsupportedEncodingException; public class PlainSaslClient implements SaslClient { private boolean completed; private CallbackHandler cbh; private String authorizationID; private String authenticationID; private byte password[]; private static byte SEPARATOR = 0; public PlainSaslClient(String authorizationID, CallbackHandler cbh) throws SaslException { completed = false; this.cbh = cbh; Object[] userInfo = getUserInfo(); this.authorizationID = authorizationID; this.authenticationID = (String) userInfo[0]; this.password = (byte[]) userInfo[1]; if (authenticationID == null || password == null) { throw new SaslException("PLAIN: authenticationID and password must be specified"); } } public byte[] evaluateChallenge(byte[] challenge) throws SaslException { if (completed) { throw new IllegalStateException("PLAIN: authentication already " + "completed"); } completed = true; try { byte authzid[] = authorizationID == null ? null : authorizationID.getBytes("UTF8"); byte authnid[] = authenticationID.getBytes("UTF8"); byte response[] = new byte[ password.length + authnid.length + 2 + // SEPARATOR (authzid != null ? authzid.length : 0) ]; int size = 0; if (authzid != null) { System.arraycopy(authzid, 0, response, 0, authzid.length); size = authzid.length; } response[size++] = SEPARATOR; System.arraycopy(authnid, 0, response, size, authnid.length); size += authnid.length; response[size++] = SEPARATOR; System.arraycopy(password, 0, response, size, password.length); clearPassword(); return response; } catch (UnsupportedEncodingException e) { throw new SaslException("PLAIN: Cannot get UTF-8 encoding of ids", e); } } public String getMechanismName() { return "PLAIN"; } public boolean hasInitialResponse() { return true; } public boolean isComplete() { return completed; } public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException { if (completed) { throw new IllegalStateException("PLAIN: this mechanism supports " + "neither integrity nor privacy"); } else { throw new IllegalStateException("PLAIN: authentication not " + "completed"); } } public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException { if (completed) { throw new IllegalStateException("PLAIN: this mechanism supports " + "neither integrity nor privacy"); } else { throw new IllegalStateException("PLAIN: authentication not " + "completed"); } } public Object getNegotiatedProperty(String propName) { if (completed) { if (propName.equals(Sasl.QOP)) { return "auth"; } else { return null; } } else { throw new IllegalStateException("PLAIN: authentication not " + "completed"); } } private void clearPassword() { if (password != null) { for (int i = 0 ; i < password.length ; i++) { password[i] = 0; } password = null; } } public void dispose() throws SaslException { clearPassword(); } protected void finalize() { clearPassword(); } private Object[] getUserInfo() throws SaslException { try { final String userPrompt = "PLAIN authentication id: "; final String pwPrompt = "PLAIN password: "; NameCallback nameCb = new NameCallback(userPrompt); PasswordCallback passwordCb = new PasswordCallback(pwPrompt, false); cbh.handle(new Callback[] { nameCb, passwordCb }); String userid = nameCb.getName(); char pwchars[] = passwordCb.getPassword(); byte pwbytes[]; if (pwchars != null) { pwbytes = (new String(pwchars)).getBytes("UTF8"); passwordCb.clearPassword(); } else { pwbytes = null; } return (new Object[] { userid, pwbytes }); } catch (IOException e) { throw new SaslException("Cannot get password", e); } catch (UnsupportedCallbackException e) { throw new SaslException("Cannot get userid/password", e); } } }