Home | History | Annotate | Download | only in sasl
      1 /*
      2  *
      3  * Licensed to the Apache Software Foundation (ASF) under one
      4  * or more contributor license agreements.  See the NOTICE file
      5  * distributed with this work for additional information
      6  * regarding copyright ownership.  The ASF licenses this file
      7  * to you under the Apache License, Version 2.0 (the
      8  * "License"); you may not use this file except in compliance
      9  * with the License.  You may obtain a copy of the License at
     10  *
     11  *   http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing,
     14  * software distributed under the License is distributed on an
     15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     16  * KIND, either express or implied.  See the License for the
     17  * specific language governing permissions and limitations
     18  * under the License.
     19  *
     20  */
     21 package org.apache.qpid.management.common.sasl;
     22 
     23 import org.apache.harmony.javax.security.auth.callback.Callback;
     24 import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
     25 import org.apache.harmony.javax.security.auth.callback.NameCallback;
     26 import org.apache.harmony.javax.security.auth.callback.PasswordCallback;
     27 import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException;
     28 import de.measite.smack.Sasl;
     29 import org.apache.harmony.javax.security.sasl.SaslClient;
     30 import org.apache.harmony.javax.security.sasl.SaslException;
     31 import java.io.IOException;
     32 import java.io.UnsupportedEncodingException;
     33 
     34 public class PlainSaslClient implements SaslClient
     35 {
     36 
     37     private boolean completed;
     38     private CallbackHandler cbh;
     39     private String authorizationID;
     40     private String authenticationID;
     41     private byte password[];
     42     private static byte SEPARATOR = 0;
     43 
     44     public PlainSaslClient(String authorizationID, CallbackHandler cbh) throws SaslException
     45     {
     46         completed = false;
     47         this.cbh = cbh;
     48         Object[] userInfo = getUserInfo();
     49         this.authorizationID = authorizationID;
     50         this.authenticationID = (String) userInfo[0];
     51         this.password = (byte[]) userInfo[1];
     52         if (authenticationID == null || password == null)
     53         {
     54             throw new SaslException("PLAIN: authenticationID and password must be specified");
     55         }
     56     }
     57 
     58     public byte[] evaluateChallenge(byte[] challenge) throws SaslException
     59     {
     60         if (completed)
     61         {
     62             throw new IllegalStateException("PLAIN: authentication already " +
     63             "completed");
     64         }
     65         completed = true;
     66         try
     67         {
     68             byte authzid[] =
     69                 authorizationID == null ? null : authorizationID.getBytes("UTF8");
     70             byte authnid[] = authenticationID.getBytes("UTF8");
     71             byte response[] =
     72                 new byte[
     73                          password.length +
     74                          authnid.length +
     75                          2 + // SEPARATOR
     76                          (authzid != null ? authzid.length : 0)
     77                          ];
     78             int size = 0;
     79             if (authzid != null) {
     80                 System.arraycopy(authzid, 0, response, 0, authzid.length);
     81                 size = authzid.length;
     82             }
     83             response[size++] = SEPARATOR;
     84             System.arraycopy(authnid, 0, response, size, authnid.length);
     85             size += authnid.length;
     86             response[size++] = SEPARATOR;
     87             System.arraycopy(password, 0, response, size, password.length);
     88             clearPassword();
     89             return response;
     90         } catch (UnsupportedEncodingException e) {
     91             throw new SaslException("PLAIN: Cannot get UTF-8 encoding of ids",
     92                     e);
     93         }
     94     }
     95 
     96     public String getMechanismName()
     97     {
     98         return "PLAIN";
     99     }
    100 
    101     public boolean hasInitialResponse()
    102     {
    103         return true;
    104     }
    105 
    106     public boolean isComplete()
    107     {
    108         return completed;
    109     }
    110 
    111     public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
    112     {
    113         if (completed) {
    114             throw new IllegalStateException("PLAIN: this mechanism supports " +
    115             "neither integrity nor privacy");
    116         } else {
    117             throw new IllegalStateException("PLAIN: authentication not " +
    118             "completed");
    119         }
    120     }
    121 
    122     public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
    123     {
    124         if (completed)
    125         {
    126             throw new IllegalStateException("PLAIN: this mechanism supports " +
    127             "neither integrity nor privacy");
    128         }
    129         else
    130         {
    131             throw new IllegalStateException("PLAIN: authentication not " +
    132             "completed");
    133         }
    134     }
    135 
    136     public Object getNegotiatedProperty(String propName)
    137     {
    138         if (completed)
    139         {
    140             if (propName.equals(Sasl.QOP))
    141             {
    142                 return "auth";
    143             }
    144             else
    145             {
    146                 return null;
    147             }
    148         }
    149         else
    150         {
    151             throw new IllegalStateException("PLAIN: authentication not " +
    152             "completed");
    153         }
    154     }
    155 
    156     private void clearPassword()
    157     {
    158         if (password != null)
    159         {
    160             for (int i = 0 ; i < password.length ; i++)
    161             {
    162                 password[i] = 0;
    163             }
    164             password = null;
    165         }
    166     }
    167 
    168     public void dispose() throws SaslException
    169     {
    170         clearPassword();
    171     }
    172 
    173     protected void finalize()
    174     {
    175         clearPassword();
    176     }
    177 
    178     private Object[] getUserInfo() throws SaslException
    179     {
    180         try
    181         {
    182             final String userPrompt = "PLAIN authentication id: ";
    183             final String pwPrompt = "PLAIN password: ";
    184             NameCallback nameCb = new NameCallback(userPrompt);
    185             PasswordCallback passwordCb = new PasswordCallback(pwPrompt, false);
    186             cbh.handle(new Callback[] { nameCb, passwordCb });
    187             String userid = nameCb.getName();
    188             char pwchars[] = passwordCb.getPassword();
    189             byte pwbytes[];
    190             if (pwchars != null)
    191             {
    192                 pwbytes = (new String(pwchars)).getBytes("UTF8");
    193                 passwordCb.clearPassword();
    194             }
    195             else
    196             {
    197                 pwbytes = null;
    198             }
    199             return (new Object[] { userid, pwbytes });
    200         }
    201         catch (IOException e)
    202         {
    203             throw new SaslException("Cannot get password", e);
    204         }
    205         catch (UnsupportedCallbackException e)
    206         {
    207             throw new SaslException("Cannot get userid/password", e);
    208         }
    209     }
    210 }
    211