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.nio.support;
28
29 import java.io.IOException;
30 import java.nio.ByteBuffer;
31 import java.util.List;
32
33 import org.apache.hc.core5.annotation.Contract;
34 import org.apache.hc.core5.annotation.ThreadingBehavior;
35 import org.apache.hc.core5.http.EntityDetails;
36 import org.apache.hc.core5.http.Header;
37 import org.apache.hc.core5.http.HeaderElements;
38 import org.apache.hc.core5.http.HttpException;
39 import org.apache.hc.core5.http.HttpHeaders;
40 import org.apache.hc.core5.http.HttpRequest;
41 import org.apache.hc.core5.http.HttpResponse;
42 import org.apache.hc.core5.http.HttpStatus;
43 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
44 import org.apache.hc.core5.http.message.BasicHttpResponse;
45 import org.apache.hc.core5.http.nio.AsyncDataConsumer;
46 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
47 import org.apache.hc.core5.http.nio.AsyncFilterChain;
48 import org.apache.hc.core5.http.nio.AsyncFilterHandler;
49 import org.apache.hc.core5.http.nio.CapacityChannel;
50 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
51 import org.apache.hc.core5.http.protocol.HttpContext;
52 import org.apache.hc.core5.net.URIAuthority;
53
54
55
56
57
58
59
60
61 @Contract(threading = ThreadingBehavior.STATELESS)
62 public abstract class AbstractAsyncServerAuthFilter<T> implements AsyncFilterHandler {
63
64 private final boolean respondImmediately;
65
66 protected AbstractAsyncServerAuthFilter(final boolean respondImmediately) {
67 this.respondImmediately = respondImmediately;
68 }
69
70
71
72
73
74
75
76
77
78 protected abstract T parseChallengeResponse(String authorizationValue, HttpContext context) throws HttpException;
79
80
81
82
83
84
85
86
87
88
89
90
91 protected abstract boolean authenticate(T challengeResponse, URIAuthority authority, String requestUri, HttpContext context);
92
93
94
95
96
97
98
99
100
101
102
103
104 protected abstract String generateChallenge(T challengeResponse, URIAuthority authority, String requestUri, HttpContext context);
105
106
107
108
109
110
111
112 protected AsyncEntityProducer generateResponseContent(final HttpResponse unauthorized) {
113 return AsyncEntityProducers.create("Unauthorized");
114 }
115
116 @Override
117 public final AsyncDataConsumer handle(
118 final HttpRequest request,
119 final EntityDetails entityDetails,
120 final HttpContext context,
121 final AsyncFilterChain.ResponseTrigger responseTrigger,
122 final AsyncFilterChain chain) throws HttpException, IOException {
123 final Header h = request.getFirstHeader(HttpHeaders.AUTHORIZATION);
124 final T challengeResponse = h != null ? parseChallengeResponse(h.getValue(), context) : null;
125
126 final URIAuthority authority = request.getAuthority();
127 final String requestUri = request.getRequestUri();
128
129 final boolean authenticated = authenticate(challengeResponse, authority, requestUri, context);
130 final Header expect = request.getFirstHeader(HttpHeaders.EXPECT);
131 final boolean expectContinue = expect != null && HeaderElements.CONTINUE.equalsIgnoreCase(expect.getValue());
132
133 if (authenticated) {
134 if (expectContinue) {
135 responseTrigger.sendInformation(new BasicClassicHttpResponse(HttpStatus.SC_CONTINUE));
136 }
137 return chain.proceed(request, entityDetails, context, responseTrigger);
138 }
139 final HttpResponse unauthorized = new BasicHttpResponse(HttpStatus.SC_UNAUTHORIZED);
140 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, generateChallenge(challengeResponse, authority, requestUri, context));
141 final AsyncEntityProducer responseContentProducer = generateResponseContent(unauthorized);
142 if (respondImmediately || expectContinue || entityDetails == null) {
143 responseTrigger.submitResponse(unauthorized, responseContentProducer);
144 return null;
145 }
146 return new AsyncDataConsumer() {
147
148 @Override
149 public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
150 capacityChannel.update(Integer.MAX_VALUE);
151 }
152
153 @Override
154 public void consume(final ByteBuffer src) throws IOException {
155 }
156
157 @Override
158 public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
159 responseTrigger.submitResponse(unauthorized, responseContentProducer);
160 }
161
162 @Override
163 public void releaseResources() {
164 if (responseContentProducer != null) {
165 responseContentProducer.releaseResources();
166 }
167 }
168
169 };
170 }
171
172 }