| /* |
| * |
| * 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); |
| } |
| } |
| } |