/* http-oauth - OAuth Extensions to jdk.httpserver Copyright (C) 2021 Ulrich Hilger This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package de.uhilger.httpserver.oauth; import com.google.gson.Gson; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import de.uhilger.httpserver.auth.realm.User; import de.uhilger.httpserver.base.HttpHelper; import de.uhilger.httpserver.base.HttpResponder; import java.io.IOException; import java.util.logging.Logger; /** * Ein Login Handler, der zur Authentifizierung ein Objekt der Klasse * BearerAuthenticator im HttpContext benoetigt. * * Der Authenticator wird mit der Methode * context.getAttributes().get(ATTR_AUTHENTICATOR); * aus dem HttpContext entnommen, d.h., der Authenticator muss zuvor dort * eingetragen werden. Das kann wie folgt vonstatten gehen: * * HttpContext context = server.createContext("/myapp/secure/service", new SomeServiceHandler()); * BearerApiAuthenticator auth = new BearerAuthenticator(); * context.setAuthenticator(auth); * * ...und danach... * * context = server.createContext("/myapp/login", new BearerLoginHandler()); * context.getAttributes().put(LoginHandler.ATTR_AUTHENTICATOR, auth); * * @author Ulrich Hilger * @version 1, 08.06.2021 */ public class BearerLoginHandler implements HttpHandler { private static final Logger logger = Logger.getLogger(BearerLoginHandler.class.getName()); public static final String ATTR_AUTHENTICATOR = "authenticator"; public static final String CACHE_CONTROL = "Cache-Control"; public static final String NO_STORE = "no-store"; public static final String PRAGMA = "Pragma"; public static final String NO_CACHE = "no-cache"; public static final String BEARER_CONTENT_TYPE = "application/json;charset=UTF-8"; /* gemaess RFC 6750 lautet die Antwort auf eine erfolgreiche Anmeldung wie folgt: HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"mF_9.B5f-4.1JqM", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" } */ /** * Login-Anfragen ausfuehren * * @param exchange das Objekt mit Informationen zu HTTP-Anfrage und -Antwort * @throws IOException */ @Override public void handle(HttpExchange exchange) throws IOException { HttpContext context = exchange.getHttpContext(); Object o = context.getAttributes().get(ATTR_AUTHENTICATOR); if (o instanceof BearerAuthenticator) { BearerAuthenticator auth = (BearerAuthenticator) o; User user = getUser(exchange); LoginResponse response = auth.login(exchange, user.getName(), user.getPassword()); handleLoginResponse(exchange, response); } else { HttpResponder r = new HttpResponder(); r.antwortSenden(exchange, 500, "No suitable authenticator."); } } /** * Die Antwort des Authenticators auf eine Login-Anfrage verarbeiten * @param exchange das Objekt mit Informationen zu HTTP-Anfrage und -Antwort * @param response die Antwort des Autehnticators * @throws IOException */ protected void handleLoginResponse(HttpExchange exchange, LoginResponse response) throws IOException { if(response != null) { setLoginHeader(exchange); HttpResponder r = new HttpResponder(); r.antwortSenden(exchange, 200, response.toJson()); } else { HttpResponder r = new HttpResponder(); r.antwortSenden(exchange, 406, "Login failed."); } } private void setLoginHeader(HttpExchange exchange) { Headers headers = exchange.getResponseHeaders(); headers.add(HttpHelper.CONTENT_TYPE, BEARER_CONTENT_TYPE); headers.add(CACHE_CONTROL, NO_STORE); headers.add(PRAGMA, NO_CACHE); } private User getUser(HttpExchange exchange) throws IOException { /* Wenn ein JSON-Inhalt im Body uebermittelt wird, steht dort evtl. etwas wie {"name": "fred", "password": "secret"} das kann wie folgt gelesen werden */ String body = new HttpHelper().bodyLesen(exchange); Gson gson = new Gson(); User user = gson.fromJson(body, User.class); return user; } }