1/*
2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 5091174
27 * @summary DigestMD5Server does not return correct value for getNegotiatedProperty(Sasl.QOP)
28 */
29
30import java.io.IOException;
31import java.util.Map;
32import java.util.HashMap;
33
34import javax.security.auth.callback.Callback;
35import javax.security.auth.callback.NameCallback;
36import javax.security.auth.callback.PasswordCallback;
37import javax.security.auth.callback.UnsupportedCallbackException;
38import javax.security.sasl.AuthorizeCallback;
39import javax.security.sasl.RealmCallback;
40import javax.security.sasl.Sasl;
41import javax.security.sasl.SaslClient;
42import javax.security.sasl.SaslException;
43import javax.security.sasl.SaslServer;
44import javax.security.auth.callback.CallbackHandler;
45
46public final class CheckNegotiatedQOPs {
47
48    static final String DIGEST_MD5 = "DIGEST-MD5";
49    private final int caseNumber;
50    private final String requestedQOPs;
51    private final String supportedQOPs;
52    private final SampleClient client;
53    private final SampleServer server;
54
55    public static void main(String[] args) throws Exception {
56
57        new CheckNegotiatedQOPs(1,  "auth",      "auth-conf,auth-int,auth")
58            .execute(false);
59        new CheckNegotiatedQOPs(2,  "auth-int",  "auth-conf,auth-int,auth")
60            .execute(false);
61        new CheckNegotiatedQOPs(3,  "auth-conf", "auth-conf,auth-int,auth")
62            .execute(false);
63        new CheckNegotiatedQOPs(4,  "auth",      "auth-int,auth")
64            .execute(false);
65        new CheckNegotiatedQOPs(5,  "auth-int",  "auth-int,auth")
66            .execute(false);
67        new CheckNegotiatedQOPs(6,  "auth-conf", "auth-int,auth")
68            .execute(true);
69        new CheckNegotiatedQOPs(7,  "auth",      "auth")
70            .execute(false);
71        new CheckNegotiatedQOPs(8,  "auth-int",  "auth")
72            .execute(true);
73        new CheckNegotiatedQOPs(9,  "auth-conf", "auth")
74            .execute(true);
75        new CheckNegotiatedQOPs(10, "auth",      null)
76            .execute(false);
77        new CheckNegotiatedQOPs(11, "auth-int",  null)
78            .execute(true);
79        new CheckNegotiatedQOPs(12, "auth-conf", null)
80            .execute(true);
81    }
82
83    private CheckNegotiatedQOPs(int caseNumber, String requestedQOPs,
84        String supportedQOPs) throws SaslException {
85
86      this.caseNumber = caseNumber;
87      this.requestedQOPs = requestedQOPs;
88      this.supportedQOPs = supportedQOPs;
89      this.client = new SampleClient(requestedQOPs);
90      this.server = new SampleServer(supportedQOPs);
91    }
92
93    private void execute(boolean expectException) throws Exception {
94
95        System.err.println ("Case #" + caseNumber);
96        System.err.println ("client requested QOPs=" + requestedQOPs);
97        System.err.println ("server supported QOPs=" + supportedQOPs);
98
99        try {
100            client.negotiate(server);
101
102            if (expectException) {
103                throw new
104                    Exception("An exception was expected but none was thrown");
105            }
106
107        } catch (SaslException e) {
108
109            if (expectException) {
110                System.err.println(e);
111                return;
112
113            } else {
114                throw e;
115            }
116        }
117
118        System.err.println("client negotiated QOP=" +
119            client.getSaslClient ().getNegotiatedProperty (Sasl.QOP));
120
121        System.err.println("server negotiated QOP=" +
122            server.getSaslServer ().getNegotiatedProperty (Sasl.QOP));
123
124        System.err.println();
125    }
126
127private final class SampleCallbackHandler implements CallbackHandler {
128
129    public void handle(Callback[] callbacks)
130        throws java.io.IOException, UnsupportedCallbackException {
131            for (int i = 0; i < callbacks.length; i++) {
132                if (callbacks[i] instanceof NameCallback) {
133                    NameCallback cb = (NameCallback)callbacks[i];
134                    cb.setName(getInput(cb.getPrompt()));
135
136                } else if (callbacks[i] instanceof PasswordCallback) {
137                    PasswordCallback cb = (PasswordCallback)callbacks[i];
138
139                    String pw = getInput(cb.getPrompt());
140                    char[] passwd = new char[pw.length()];
141                    pw.getChars(0, passwd.length, passwd, 0);
142
143                    cb.setPassword(passwd);
144
145                } else if (callbacks[i] instanceof RealmCallback) {
146                    RealmCallback cb = (RealmCallback)callbacks[i];
147                    //cb.setText(getInput(cb.getPrompt()));
148                    cb.setText("127.0.0.1");
149
150                } else if (callbacks[i] instanceof AuthorizeCallback) {
151                    AuthorizeCallback cb = (AuthorizeCallback)callbacks[i];
152                    cb.setAuthorized(true);
153
154                } else {
155                    throw new UnsupportedCallbackException(callbacks[i]);
156                }
157            }
158    }
159
160    /**
161     * In real world apps, this would typically be a TextComponent or
162     * similar widget.
163     */
164    private String getInput(String prompt) throws IOException {
165        return "dummy-value";
166    }
167}
168
169private final class SampleClient {
170
171    private final SaslClient saslClient;
172
173    public SampleClient(String requestedQOPs) throws SaslException {
174
175        Map<String,String> properties = new HashMap<String,String>();
176
177        if (requestedQOPs != null) {
178            properties.put(Sasl.QOP, requestedQOPs);
179        }
180        saslClient = Sasl.createSaslClient(new String[]{ DIGEST_MD5 }, null,
181            "local", "127.0.0.1", properties, new SampleCallbackHandler());
182    }
183
184    public SaslClient getSaslClient() {
185        return saslClient;
186    }
187
188    public void negotiate(SampleServer server) throws SaslException {
189
190        byte[] challenge;
191        byte[] response;
192
193        response = (saslClient.hasInitialResponse () ?
194                  saslClient.evaluateChallenge (new byte [0]) : new byte [0]);
195
196        while (! saslClient.isComplete()) {
197            challenge = server.evaluate(response);
198            response = saslClient.evaluateChallenge(challenge);
199        }
200   }
201}
202
203private final class SampleServer {
204
205    private final SaslServer saslServer;
206
207    public SampleServer(String supportedQOPs) throws SaslException {
208
209        Map<String,String> properties = new HashMap<String,String>();
210
211        if (supportedQOPs != null) {
212            properties.put(Sasl.QOP, supportedQOPs);
213        }
214        saslServer = Sasl.createSaslServer(DIGEST_MD5, "local", "127.0.0.1",
215            properties, new SampleCallbackHandler());
216    }
217
218    public SaslServer getSaslServer() {
219        return saslServer;
220    }
221
222    public byte[] evaluate(byte[] response) throws SaslException {
223
224      if (saslServer.isComplete()) {
225         throw new SaslException ("Server is already complete");
226      }
227
228      return saslServer.evaluateResponse(response);
229   }
230}
231}
232