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