• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PlainSaslClient(String authorizationID, CallbackHandler cbh)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 
evaluateChallenge(byte[] challenge)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 
getMechanismName()96     public String getMechanismName()
97     {
98         return "PLAIN";
99     }
100 
hasInitialResponse()101     public boolean hasInitialResponse()
102     {
103         return true;
104     }
105 
isComplete()106     public boolean isComplete()
107     {
108         return completed;
109     }
110 
unwrap(byte[] incoming, int offset, int len)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 
wrap(byte[] outgoing, int offset, int len)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 
getNegotiatedProperty(String propName)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 
clearPassword()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 
dispose()168     public void dispose() throws SaslException
169     {
170         clearPassword();
171     }
172 
finalize()173     protected void finalize()
174     {
175         clearPassword();
176     }
177 
getUserInfo()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