0N/A/*
2362N/A * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 6287172
0N/A * @summary SASL + Digest-MD5, charset quoted
0N/A */
0N/A
0N/Aimport java.io.BufferedReader;
0N/Aimport java.io.InputStreamReader;
0N/Aimport java.io.IOException;
0N/Aimport java.util.Map;
0N/Aimport java.util.TreeMap;
0N/Aimport java.util.logging.Logger;
0N/Aimport javax.security.auth.callback.Callback;
0N/Aimport javax.security.auth.callback.NameCallback;
0N/Aimport javax.security.auth.callback.PasswordCallback;
0N/Aimport javax.security.auth.callback.UnsupportedCallbackException;
0N/Aimport javax.security.sasl.RealmCallback;
0N/Aimport javax.security.sasl.Sasl;
0N/Aimport javax.security.sasl.SaslClient;
0N/Aimport javax.security.sasl.SaslException;
0N/Aimport javax.security.sasl.SaslServer;
0N/Aimport javax.security.auth.callback.CallbackHandler;
0N/Aimport com.sun.security.auth.callback.DialogCallbackHandler;
0N/Aimport com.sun.security.auth.callback.TextCallbackHandler;
0N/A
0N/A/*
0N/A * According to RFC 2831, DIGEST-MD5 servers must generate challenge strings
0N/A * whose charset and algorithm values are not enclosed within quotes.
0N/A * For example,
0N/A * challenge: realm="127.0.0.1",nonce="8GBOabRGeIqZB5BiaYJ1NDTuteV+D7n+qbSTH1fo",qop="auth",charset=utf-8,algorithm=md5-sess
0N/A */
0N/Apublic class NoQuoteParams {
0N/A
0N/A private static Logger logger = Logger.getLogger("global");
0N/A private static final String DIGEST_MD5 = "DIGEST-MD5";
0N/A private static final byte[] EMPTY = new byte[0];
0N/A
0N/A private static CallbackHandler authCallbackHandler =
0N/A new SampleCallbackHandler();
0N/A
0N/A public static void main(String[] args) throws Exception {
0N/A
0N/A Map<String, String> props = new TreeMap<String, String>();
0N/A props.put(Sasl.QOP, "auth");
0N/A
0N/A // client
0N/A SaslClient client = Sasl.createSaslClient(new String[]{ DIGEST_MD5 },
0N/A "user1", "xmpp", "127.0.0.1", props, authCallbackHandler);
0N/A if (client == null) {
0N/A throw new Exception("Unable to find client implementation for: " +
0N/A DIGEST_MD5);
0N/A }
0N/A
0N/A byte[] response = client.hasInitialResponse()
0N/A ? client.evaluateChallenge(EMPTY) : EMPTY;
0N/A logger.info("initial: " + new String(response));
0N/A
0N/A // server
0N/A byte[] challenge = null;
0N/A SaslServer server = Sasl.createSaslServer(DIGEST_MD5, "xmpp",
0N/A "127.0.0.1", props, authCallbackHandler);
0N/A if (server == null) {
0N/A throw new Exception("Unable to find server implementation for: " +
0N/A DIGEST_MD5);
0N/A }
0N/A
0N/A if (!client.isComplete() || !server.isComplete()) {
0N/A challenge = server.evaluateResponse(response);
0N/A
0N/A logger.info("challenge: " + new String(challenge));
0N/A
0N/A if (challenge != null) {
0N/A response = client.evaluateChallenge(challenge);
0N/A }
0N/A }
0N/A
0N/A String challengeString = new String(challenge, "UTF-8").toLowerCase();
0N/A
0N/A if (challengeString.indexOf("\"md5-sess\"") > 0 ||
0N/A challengeString.indexOf("\"utf-8\"") > 0) {
0N/A throw new Exception("The challenge string's charset and " +
0N/A "algorithm values must not be enclosed within quotes");
0N/A }
0N/A
0N/A client.dispose();
0N/A server.dispose();
0N/A }
0N/A}
0N/A
0N/Aclass SampleCallbackHandler implements CallbackHandler {
0N/A
0N/A public void handle(Callback[] callbacks)
0N/A throws java.io.IOException, UnsupportedCallbackException {
0N/A for (int i = 0; i < callbacks.length; i++) {
0N/A if (callbacks[i] instanceof NameCallback) {
0N/A NameCallback cb = (NameCallback)callbacks[i];
0N/A cb.setName(getInput(cb.getPrompt()));
0N/A
0N/A } else if (callbacks[i] instanceof PasswordCallback) {
0N/A PasswordCallback cb = (PasswordCallback)callbacks[i];
0N/A
0N/A String pw = getInput(cb.getPrompt());
0N/A char[] passwd = new char[pw.length()];
0N/A pw.getChars(0, passwd.length, passwd, 0);
0N/A
0N/A cb.setPassword(passwd);
0N/A
0N/A } else if (callbacks[i] instanceof RealmCallback) {
0N/A RealmCallback cb = (RealmCallback)callbacks[i];
0N/A cb.setText(getInput(cb.getPrompt()));
0N/A
0N/A } else {
0N/A throw new UnsupportedCallbackException(callbacks[i]);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * In real world apps, this would typically be a TextComponent or
0N/A * similar widget.
0N/A */
0N/A private String getInput(String prompt) throws IOException {
0N/A return "dummy-value";
0N/A }
0N/A}