OAuth-Unterstuetzung fuer jdk.httpserver
ulrich
2021-06-08 9dc2865a7408c33f403056f408690c227bdfe690
commit | author | age
7ecde3 1 /*
U 2   http-oauth - OAuth Extensions to jdk.httpserver
3   Copyright (C) 2021  Ulrich Hilger
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU Affero General Public License as
7   published by the Free Software Foundation, either version 3 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18 package de.uhilger.httpserver.oauth;
19
20 import com.google.gson.Gson;
21 import com.sun.net.httpserver.Headers;
22 import com.sun.net.httpserver.HttpContext;
23 import com.sun.net.httpserver.HttpExchange;
24 import com.sun.net.httpserver.HttpHandler;
25 import de.uhilger.httpserver.auth.realm.User;
26 import de.uhilger.httpserver.base.handler.HttpHelper;
27 import de.uhilger.httpserver.base.handler.HttpResponder;
28 import java.io.IOException;
29 import java.util.logging.Logger;
30
31 /**
32  * Ein Login Handler, der zur Authentifizierung ein Objekt der Klasse 
33  * BearerAuthenticator im HttpContext benoetigt.
34  * 
35  * Der Authenticator wird mit der Methode 
36  * context.getAttributes().get(ATTR_AUTHENTICATOR); 
37  * aus dem HttpContext entnommen, d.h., der Authenticator muss zuvor dort 
38  * eingetragen werden. Das kann wie folgt vonstatten gehen:
39  * 
40  * HttpContext context = server.createContext("/myapp/secure/service", new SomeServiceHandler());
41  * BearerApiAuthenticator auth = new BearerAuthenticator();
42  * context.setAuthenticator(auth);
43  * 
44  * ...und danach...
45  * 
46  * context = server.createContext("/myapp/login", new BearerLoginHandler());
47  * context.getAttributes().put(LoginHandler.ATTR_AUTHENTICATOR, auth);
48  * 
49  * @author Ulrich Hilger
50  * @version 1, 08.06.2021
51  */
52 public class BearerLoginHandler implements HttpHandler {
53   
54   private static final Logger logger = Logger.getLogger(BearerLoginHandler.class.getName());
55   
56   public static final String ATTR_AUTHENTICATOR = "authenticator";
57   
58   public static final String CACHE_CONTROL = "Cache-Control";
59   public static final String NO_STORE = "no-store";
60   public static final String PRAGMA = "Pragma";
61   public static final String NO_CACHE = "no-cache";
62   public static final String BEARER_CONTENT_TYPE = "application/json;charset=UTF-8";
63   
64   /*
65     gemaess RFC 6750 lautet die Antwort auf eine erfolgreiche Anmeldung
66     wie folgt:
67   
68      HTTP/1.1 200 OK
69      Content-Type: application/json;charset=UTF-8
70      Cache-Control: no-store
71      Pragma: no-cache
72
73      {
74        "access_token":"mF_9.B5f-4.1JqM",
75        "token_type":"Bearer",
76        "expires_in":3600,
77        "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
78      }
79   */
80   @Override
81   public void handle(HttpExchange exchange) throws IOException {
82     HttpContext context = exchange.getHttpContext();
83     Object o = context.getAttributes().get(ATTR_AUTHENTICATOR);
84     if (o instanceof BearerAuthenticator) {
85       BearerAuthenticator auth = (BearerAuthenticator) o;
86       User user = getUser(exchange);
87       LoginResponse response = auth.login(user.getName(), user.getPassword());
88       handleLoginResponse(exchange, response);
89     } else {
90       HttpResponder r = new HttpResponder();
91       r.antwortSenden(exchange, 500, "No suitable authenticator.");
92     }
93   }
94   
95   protected void handleLoginResponse(HttpExchange exchange, LoginResponse response) throws IOException {
96     if(response != null) {
97       setLoginHeader(exchange);
98       HttpResponder r = new HttpResponder();
99       r.antwortSenden(exchange, 200, response.toJson());
100     } else {
101       HttpResponder r = new HttpResponder();
102       r.antwortSenden(exchange, 406, "Login failed.");
103     }
104   }
105   
106   private void setLoginHeader(HttpExchange exchange) {
107     Headers headers = exchange.getResponseHeaders();
108     headers.add(HttpHelper.CONTENT_TYPE, BEARER_CONTENT_TYPE);
109     headers.add(CACHE_CONTROL, NO_STORE);
110     headers.add(PRAGMA, NO_CACHE);
111   } 
112   
113   private User getUser(HttpExchange exchange) throws IOException {
114     /*
115     Wenn ein JSON-Inhalt im Body uebermittelt wird, steht
116     dort evtl. etwas wie
117     {"name": "fred", "password": "secret"}
118     das kann wie folgt gelesen werden
119      */
120     String body = new HttpHelper().bodyLesen(exchange);
121     Gson gson = new Gson();
122     User user = gson.fromJson(body, User.class);
123     return user;
124   }
125   
126   
127 }