1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.core5.http.io.support;
28
29 import java.io.IOException;
30
31 import org.apache.hc.core5.annotation.Contract;
32 import org.apache.hc.core5.annotation.ThreadingBehavior;
33 import org.apache.hc.core5.http.ClassicHttpRequest;
34 import org.apache.hc.core5.http.ClassicHttpResponse;
35 import org.apache.hc.core5.http.Header;
36 import org.apache.hc.core5.http.HeaderElements;
37 import org.apache.hc.core5.http.HttpEntity;
38 import org.apache.hc.core5.http.HttpException;
39 import org.apache.hc.core5.http.HttpHeaders;
40 import org.apache.hc.core5.http.HttpResponse;
41 import org.apache.hc.core5.http.HttpStatus;
42 import org.apache.hc.core5.http.io.HttpFilterChain;
43 import org.apache.hc.core5.http.io.HttpFilterHandler;
44 import org.apache.hc.core5.http.io.entity.EntityUtils;
45 import org.apache.hc.core5.http.io.entity.StringEntity;
46 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
47 import org.apache.hc.core5.http.protocol.HttpContext;
48 import org.apache.hc.core5.net.URIAuthority;
49
50
51
52
53
54
55
56
57 @Contract(threading = ThreadingBehavior.STATELESS)
58 public abstract class AbstractHttpServerAuthFilter<T> implements HttpFilterHandler {
59
60 private final boolean respondImmediately;
61
62 protected AbstractHttpServerAuthFilter(final boolean respondImmediately) {
63 this.respondImmediately = respondImmediately;
64 }
65
66
67
68
69
70
71
72
73
74 protected abstract T parseChallengeResponse(String authorizationValue, HttpContext context) throws HttpException;
75
76
77
78
79
80
81
82
83
84
85
86
87 protected abstract boolean authenticate(T challengeResponse, URIAuthority authority, String requestUri, HttpContext context);
88
89
90
91
92
93
94
95
96
97
98
99
100 protected abstract String generateChallenge(T challengeResponse, URIAuthority authority, String requestUri, HttpContext context);
101
102
103
104
105
106
107
108 protected HttpEntity generateResponseContent(final HttpResponse unauthorized) {
109 return new StringEntity("Unauthorized");
110 }
111
112 @Override
113 public final void handle(
114 final ClassicHttpRequest request,
115 final HttpFilterChain.ResponseTrigger responseTrigger,
116 final HttpContext context,
117 final HttpFilterChain chain) throws HttpException, IOException {
118 final Header h = request.getFirstHeader(HttpHeaders.AUTHORIZATION);
119 final T challengeResponse = h != null ? parseChallengeResponse(h.getValue(), context) : null;
120
121 final URIAuthority authority = request.getAuthority();
122 final String requestUri = request.getRequestUri();
123
124 final boolean authenticated = authenticate(challengeResponse, authority, requestUri, context);
125 final Header expect = request.getFirstHeader(HttpHeaders.EXPECT);
126 final boolean expectContinue = expect != null && HeaderElements.CONTINUE.equalsIgnoreCase(expect.getValue());
127
128 if (authenticated) {
129 if (expectContinue) {
130 responseTrigger.sendInformation(new BasicClassicHttpResponse(HttpStatus.SC_CONTINUE));
131 }
132 chain.proceed(request, responseTrigger, context);
133 } else {
134 final ClassicHttpResponse unauthorized = new BasicClassicHttpResponse(HttpStatus.SC_UNAUTHORIZED);
135 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, generateChallenge(challengeResponse, authority, requestUri, context));
136 final HttpEntity responseContent = generateResponseContent(unauthorized);
137 unauthorized.setEntity(responseContent);
138 if (respondImmediately || expectContinue || request.getEntity() == null) {
139
140 responseTrigger.submitResponse(unauthorized);
141
142 EntityUtils.consume(request.getEntity());
143 } else {
144
145 EntityUtils.consume(request.getEntity());
146
147 responseTrigger.submitResponse(unauthorized);
148 }
149 }
150 }
151 }