1/*
2 * Copyright (c) 2015, 2016, 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
24import com.sun.net.httpserver.HttpExchange;
25import com.sun.net.httpserver.HttpHandler;
26import com.sun.net.httpserver.HttpServer;
27import java.io.BufferedReader;
28import java.io.InputStreamReader;
29import java.io.IOException;
30import java.io.InputStream;
31import java.net.Authenticator;
32import java.net.InetSocketAddress;
33import java.net.PasswordAuthentication;
34import java.net.URL;
35import java.net.URLConnection;
36import java.util.List;
37import sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback;
38
39/*
40 * @test
41 * @bug 8137174
42 * @modules java.base/sun.net.www.protocol.http.ntlm
43 *          jdk.httpserver
44 * @summary Checks if NTLM auth works fine if security manager set
45 * @run main/othervm/java.security.policy=NTLMAuthWithSM.policy NTLMAuthWithSM
46 */
47public class NTLMAuthWithSM {
48
49    public static void main(String[] args) throws Exception {
50        // security manager is required
51        if (System.getSecurityManager() == null) {
52            throw new RuntimeException("Security manager not specified");
53        }
54
55        if (System.getProperty("os.name").startsWith("Windows")) {
56            // disable transparent NTLM authentication on Windows
57            NTLMAuthenticationCallback.setNTLMAuthenticationCallback(
58                    new NTLMAuthenticationCallbackImpl());
59        }
60
61        try (LocalHttpServer server = LocalHttpServer.startServer()) {
62            // set authenticator
63            Authenticator.setDefault(new AuthenticatorImpl());
64
65            String url = String.format("http://localhost:%d/test/",
66                    server.getPort());
67
68            // load a document which is protected with NTML authentication
69            System.out.println("load() called: " + url);
70            URLConnection conn = new URL(url).openConnection();
71            try (BufferedReader reader = new BufferedReader(
72                    new InputStreamReader(conn.getInputStream()))) {
73
74                String line = reader.readLine();
75                if (line == null) {
76                    throw new IOException("Couldn't read a response");
77                }
78                do {
79                    System.out.println(line);
80                } while ((line = reader.readLine()) != null);
81            }
82        }
83
84        System.out.println("Test passed");
85    }
86
87    private static class AuthenticatorImpl extends Authenticator {
88
89        @Override
90        public PasswordAuthentication getPasswordAuthentication() {
91            System.out.println("getPasswordAuthentication() called, scheme: "
92                    + getRequestingScheme());
93            if (getRequestingScheme().equalsIgnoreCase("ntlm")) {
94                return new PasswordAuthentication("test", "test".toCharArray());
95            }
96            return null;
97        }
98    }
99
100    // local http server which pretends to support NTLM auth
101    static class LocalHttpServer implements HttpHandler, AutoCloseable {
102
103        private final HttpServer server;
104
105        private LocalHttpServer(HttpServer server) {
106            this.server = server;
107        }
108
109        static LocalHttpServer startServer() throws IOException {
110            HttpServer httpServer = HttpServer.create(
111                    new InetSocketAddress(0), 0);
112            LocalHttpServer localHttpServer = new LocalHttpServer(httpServer);
113            localHttpServer.start();
114
115            return localHttpServer;
116        }
117
118        void start() {
119            server.createContext("/test", this);
120            server.start();
121            System.out.println("HttpServer: started on port " + getPort());
122        }
123
124        void stop() {
125            server.stop(0);
126            System.out.println("HttpServer: stopped");
127        }
128
129        int getPort() {
130            return server.getAddress().getPort();
131        }
132
133        @Override
134        public void handle(HttpExchange t) throws IOException {
135            System.out.println("HttpServer: handle connection");
136
137            // read a request
138            try (InputStream is = t.getRequestBody()) {
139                while (is.read() > 0);
140            }
141
142            try {
143                List<String> headers = t.getRequestHeaders()
144                        .get("Authorization");
145                if (headers != null && !headers.isEmpty()
146                        && headers.get(0).trim().contains("NTLM")) {
147                    byte[] output = "hello".getBytes();
148                    t.sendResponseHeaders(200, output.length);
149                    t.getResponseBody().write(output);
150                    System.out.println("HttpServer: return 200");
151                } else {
152                    t.getResponseHeaders().set("WWW-Authenticate", "NTLM");
153                    byte[] output = "forbidden".getBytes();
154                    t.sendResponseHeaders(401, output.length);
155                    t.getResponseBody().write(output);
156                    System.out.println("HttpServer: return 401");
157                }
158            } catch (IOException e) {
159                System.out.println("HttpServer: exception: " + e);
160                System.out.println("HttpServer: return 500");
161                t.sendResponseHeaders(500, 0);
162            } finally {
163                t.close();
164            }
165        }
166
167        @Override
168        public void close() {
169            stop();
170        }
171    }
172
173    private static class NTLMAuthenticationCallbackImpl
174            extends NTLMAuthenticationCallback {
175
176        // don't trust any site, so that no transparent NTLM auth happens
177        @Override
178        public boolean isTrustedSite(URL url) {
179            System.out.println(
180                    "NTLMAuthenticationCallbackImpl.isTrustedSite() called: "
181                        + "return false");
182            return false;
183        }
184    }
185}
186