Skip to content

Commit f5ba2e3

Browse files
committed
Authorization validation
Plus, a couple of minor tweaks.
1 parent c4b4be8 commit f5ba2e3

File tree

4 files changed

+97
-23
lines changed

4 files changed

+97
-23
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package examples;
2+
3+
import express.Express;
4+
import express.http.request.Authorization;
5+
import express.utils.Status;
6+
7+
public class AuthorizationExamples
8+
{
9+
public static void main(String[] args)
10+
{
11+
Express app = new Express();
12+
13+
app.get("/", (req, res) -> {
14+
if(Authorization.validate(req, Authorization.validator("Basic", "123456789"))) {
15+
res.send("You are authorized!");
16+
} else {
17+
res.setStatus(Status._401);
18+
res.send();
19+
}
20+
});
21+
22+
app.listen(() -> System.out.println("Listening!"));
23+
}
24+
}

src/main/java/express/http/Cookie.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,7 @@ public boolean equals(Object obj) {
203203
if (!other.getExpire().equals(this.getExpire())) return false;
204204
if (other.getMaxAge() != this.getMaxAge()) return false;
205205
if (!other.getSameSite().equals(this.getSameSite())) return false;
206-
if (!other.getPath().equals(this.getPath())) return false;
207-
208-
return true;
206+
return other.getPath().equals(this.getPath());
209207
}
210208
return super.equals(obj);
211209
}
Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,91 @@
11
package express.http.request;
22

33
import java.util.Base64;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.function.Predicate;
7+
import java.util.stream.Collectors;
8+
import java.util.stream.Stream;
49

510
/**
611
* @author Simon Reinisch
712
* <p>
8-
* Class for an http-authorization
13+
* Represents an HTTP Authorization header value
14+
* and encapsulates authorization data
915
*/
1016
public class Authorization {
11-
17+
18+
public static final String HEADER_NAME = "Authorization";
19+
1220
private final String TYPE;
1321
private final String DATA;
14-
22+
1523
Authorization(String authHeader) {
16-
int index = authHeader.indexOf(' ');
17-
this.TYPE = authHeader.substring(0, index);
18-
this.DATA = authHeader.substring(index + 1);
24+
String[] parts = Stream.of(authHeader.split(" "))
25+
.filter(s -> !s.isEmpty())
26+
.toArray(String[]::new);
27+
28+
this.TYPE = parts[0];
29+
this.DATA = parts[1];
1930
}
20-
31+
2132
/**
2233
* @return The Authorization type
2334
*/
2435
public String getType() {
2536
return TYPE;
2637
}
27-
38+
2839
/**
2940
* @return The Authorization data
3041
*/
3142
public String getData() {
3243
return DATA;
3344
}
34-
45+
3546
/**
3647
* @return The Authorization data base64 decoded
3748
*/
3849
public String getDataBase64Decoded() {
3950
return new String(Base64.getDecoder().decode(DATA));
4051
}
52+
53+
/**
54+
* @return A list of authorization options that are contained in the given request.
55+
* Authorization options can be separated by a comma in the Authorization header.
56+
*/
57+
public static List<Authorization> get(Request req) {
58+
List<String> headerVals = req.getHeader(HEADER_NAME);
59+
if(!headerVals.isEmpty()) {
60+
String authHeader = headerVals.get(0);
61+
return Collections.unmodifiableList(Stream.of(authHeader.split(","))
62+
.map(Authorization::new).collect(Collectors.toList()));
63+
}
64+
return Collections.emptyList();
65+
}
66+
67+
/**
68+
* Validates the given request authentication using each of the given predicates.
69+
* If any of the predicates returns <code>true</code>, the request is counted as
70+
* validly authorized and the method returns <code>true</code>.
71+
*/
72+
@SafeVarargs
73+
public static boolean validate(Request req, Predicate<Authorization>... validators) {
74+
for(Authorization auth : get(req)) {
75+
for(Predicate<Authorization> validator : validators) {
76+
if(validator.test(auth)) return true;
77+
}
78+
}
79+
return false;
80+
}
81+
82+
/**
83+
* @param type The expected type of the authorization
84+
* @param data The expected data of the authorization
85+
* @return A predicate that can be used with {@link Authorization#validate(Request, Predicate...)}
86+
* to test for a single type of authorization
87+
*/
88+
public static Predicate<Authorization> validator(String type, String data) {
89+
return (auth -> auth.getType().equals(type) && auth.getData().equals(data));
90+
}
4191
}

src/main/java/express/http/request/Request.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
import java.nio.file.Path;
1919
import java.time.Instant;
2020
import java.time.format.DateTimeFormatter;
21+
import java.util.Collections;
2122
import java.util.HashMap;
2223
import java.util.List;
24+
import java.util.Optional;
2325

2426
/**
2527
* @author Simon Reinisch
2628
* <p>
27-
* Class for http-request content.
29+
* Class encapsulating HTTP request data
2830
*/
2931
public class Request {
3032

@@ -43,8 +45,8 @@ public class Request {
4345

4446
private final HashMap<String, Object> MIDDLEWARE; // Middleware Data
4547
private final HashMap<String, Cookie> COOKIES; // Request cookies
46-
private final HashMap<String, String> QUERYS; // URL Query's
47-
private final HashMap<String, String> FORM_QUERYS; // Form Query's (application/x-www-form-urlencoded)
48+
private final HashMap<String, String> QUERIES; // URL Query parameters
49+
private final HashMap<String, String> FORM_QUERIES; // Form query parameters (application/x-www-form-urlencoded)
4850

4951
private HashMap<String, String> params; // URL Params, would be added in ExpressFilterImpl
5052
private String context; // Context which matched
@@ -76,12 +78,12 @@ public Request(HttpExchange exchange, Express express) {
7678
this.AUTH = HEADERS.get("Authorization") == null ? null : new Authorization(HEADERS.get("Authorization").get(0));
7779

7880
// Check if the request contains x-www-form-urlencoded form data
79-
this.FORM_QUERYS = CONTENT_TYPE.startsWith("application/x-www-form-urlencoded")
81+
this.FORM_QUERIES = CONTENT_TYPE.startsWith("application/x-www-form-urlencoded")
8082
? RequestUtils.parseRawQuery(Utils.streamToString(BODY))
8183
: new HashMap<>();
8284

8385
// Parse query and cookies, both returns not null if there is nothing
84-
this.QUERYS = RequestUtils.parseRawQuery(exchange.getRequestURI().getRawQuery());
86+
this.QUERIES = RequestUtils.parseRawQuery(exchange.getRequestURI().getRawQuery());
8587
this.COOKIES = RequestUtils.parseCookies(HEADERS);
8688
}
8789

@@ -339,7 +341,7 @@ public boolean hasAuthorization() {
339341
* @return The value, null if there is none.
340342
*/
341343
public String getFormQuery(String name) {
342-
return FORM_QUERYS.get(name);
344+
return FORM_QUERIES.get(name);
343345
}
344346

345347
/**
@@ -359,7 +361,7 @@ public String getParam(String param) {
359361
* @return The value, null if there is none.
360362
*/
361363
public String getQuery(String name) {
362-
return QUERYS.get(name);
364+
return QUERIES.get(name);
363365
}
364366

365367
/**
@@ -368,7 +370,7 @@ public String getQuery(String name) {
368370
* @return An entire list of key-values
369371
*/
370372
public HashMap<String, String> getFormQuerys() {
371-
return FORM_QUERYS;
373+
return FORM_QUERIES;
372374
}
373375

374376
/**
@@ -411,17 +413,17 @@ public void setContext(String context) {
411413
* @return An entire list of key-values
412414
*/
413415
public HashMap<String, String> getQuerys() {
414-
return QUERYS;
416+
return QUERIES;
415417
}
416418

417419
/**
418420
* Returns an header value.
419421
*
420422
* @param header The header name
421-
* @return An list with values.
423+
* @return A list with values.
422424
*/
423425
public List<String> getHeader(String header) {
424-
return HEADERS.get(header);
426+
return Optional.ofNullable(HEADERS.get(header)).orElse(Collections.emptyList());
425427
}
426428

427429
/**

0 commit comments

Comments
 (0)