Skip to content

Commit 5478bd1

Browse files
Merge branch 'release/0.7.0'
2 parents f631ad7 + 86d66cf commit 5478bd1

File tree

8 files changed

+70
-26
lines changed

8 files changed

+70
-26
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ jobs:
5050
server-id: ossrh
5151
server-username: MAVEN_USERNAME
5252
server-password: MAVEN_PASSWORD
53-
gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
54-
gpg-passphrase: MAVEN_GPG_PASSPHRASE
5553
- name: Deploy to OSSRH
5654
if: startsWith(github.ref, 'refs/tags/')
5755
run: mvn -B deploy -Psign,deploy-central -DskipTests --no-transfer-progress
@@ -68,4 +66,4 @@ jobs:
6866
if: startsWith(github.ref, 'refs/tags/')
6967
uses: softprops/action-gh-release@v1
7068
with:
71-
generate_release_notes: true
69+
generate_release_notes: true

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Configure your authorization server to allow `http://127.0.0.1/*` as a redirect
2727
// this library will just perform the Authorization Flow:
2828
var httpResponse = TinyOAuth2.client("oauth-client-id")
2929
.withTokenEndpoint(URI.create("https://login.example.com/oauth2/token"))
30+
.withRequestTimeout(Duration.ofSeconds(10)) // optional
3031
.authFlow(URI.create("https://login.example.com/oauth2/authorize"))
3132
.authorize(uri -> System.out.println("Please login on " + uri));
3233

@@ -38,6 +39,17 @@ if (httpResponse.statusCode() == 200) {
3839
}
3940
```
4041

42+
If you wish to use a proxy or your own set of root certificates, provide your own JDK [http client](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html):
43+
```java
44+
var httpClient = HttpClient.newBuilder()
45+
.proxy(ProxySelector.of(InetSocketAddress.createUnresolved("https:\\example.com",1337)))
46+
.build();
47+
var httpResponse = TinyOAuth2.client("oauth-client-id")
48+
.withTokenEndpoint(URI.create("https://login.example.com/oauth2/token"))
49+
.authFlow(URI.create("https://login.example.com/oauth2/authorize"))
50+
.authorize(httpClient, uri -> System.out.println("Please login on " + uri));
51+
```
52+
4153
If your authorization server doesn't allow wildcards, you can also configure a fixed path (and even port) via e.g. `setRedirectPath("/callback")` and `setRedirectPorts(8080)`.
4254

4355
## Why this library?

pom.xml

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>io.github.coffeelibs</groupId>
77
<artifactId>tiny-oauth2-client</artifactId>
8-
<version>0.6.0</version>
8+
<version>0.7.0</version>
99
<name>Tiny OAuth2 Client</name>
1010
<description>Zero Dependency RFC 8252 Authorization Flow</description>
1111
<inceptionYear>2022</inceptionYear>
@@ -48,13 +48,13 @@
4848
<dependency>
4949
<groupId>org.junit.jupiter</groupId>
5050
<artifactId>junit-jupiter</artifactId>
51-
<version>5.8.2</version>
51+
<version>5.10.0</version>
5252
<scope>test</scope>
5353
</dependency>
5454
<dependency>
5555
<groupId>org.mockito</groupId>
5656
<artifactId>mockito-core</artifactId>
57-
<version>4.4.0</version>
57+
<version>5.5.0</version>
5858
<scope>test</scope>
5959
</dependency>
6060
</dependencies>
@@ -64,23 +64,20 @@
6464
<plugin>
6565
<groupId>org.apache.maven.plugins</groupId>
6666
<artifactId>maven-compiler-plugin</artifactId>
67-
<version>3.10.1</version>
67+
<version>3.11.0</version>
6868
<configuration>
6969
<release>11</release>
7070
</configuration>
7171
</plugin>
7272
<plugin>
7373
<groupId>org.apache.maven.plugins</groupId>
7474
<artifactId>maven-surefire-plugin</artifactId>
75-
<version>3.0.0-M5</version>
76-
<configuration>
77-
<useModulePath>false</useModulePath> <!-- avoid problems with Mockito -->
78-
</configuration>
75+
<version>3.1.2</version>
7976
</plugin>
8077
<plugin>
8178
<groupId>org.apache.maven.plugins</groupId>
8279
<artifactId>maven-source-plugin</artifactId>
83-
<version>3.2.1</version>
80+
<version>3.3.0</version>
8481
<executions>
8582
<execution>
8683
<id>attach-sources</id>
@@ -93,7 +90,7 @@
9390
<plugin>
9491
<groupId>org.apache.maven.plugins</groupId>
9592
<artifactId>maven-javadoc-plugin</artifactId>
96-
<version>3.3.2</version>
93+
<version>3.6.0</version>
9794
<executions>
9895
<execution>
9996
<id>attach-javadocs</id>

src/main/java/io/github/coffeelibs/tinyoauth2client/TinyOAuth2Client.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.net.http.HttpClient;
99
import java.net.http.HttpRequest;
1010
import java.net.http.HttpResponse;
11+
import java.time.Duration;
1112
import java.util.Map;
1213
import java.util.Objects;
1314
import java.util.concurrent.CompletableFuture;
@@ -21,6 +22,8 @@
2122
@ApiStatus.Experimental
2223
public class TinyOAuth2Client {
2324

25+
private static final Duration DEFAULT_REQUEST_TIMEOUT = Duration.ofSeconds(30);
26+
2427
/**
2528
* @see <a href="https://datatracker.ietf.org/doc/html/rfc6749#section-2.2">Client Identifier</a>
2629
*/
@@ -31,9 +34,29 @@ public class TinyOAuth2Client {
3134
*/
3235
final URI tokenEndpoint;
3336

37+
/**
38+
* Timeout of HTTP requests
39+
*/
40+
final Duration requestTimeout;
41+
3442
TinyOAuth2Client(String clientId, URI tokenEndpoint) {
43+
this(clientId, tokenEndpoint, DEFAULT_REQUEST_TIMEOUT);
44+
}
45+
46+
private TinyOAuth2Client(String clientId, URI tokenEndpoint, Duration requestTimeout) {
3547
this.clientId = Objects.requireNonNull(clientId);
3648
this.tokenEndpoint = Objects.requireNonNull(tokenEndpoint);
49+
this.requestTimeout = Objects.requireNonNull(requestTimeout);
50+
}
51+
52+
/**
53+
* Creates a new OAuth2 Client with the specified request timeout
54+
* @param requestTimeout HTTP request timeout
55+
* @return A new client
56+
* @since 0.7.0
57+
*/
58+
public TinyOAuth2Client withRequestTimeout(Duration requestTimeout) {
59+
return new TinyOAuth2Client(this.clientId, this.tokenEndpoint, requestTimeout);
3760
}
3861

3962
/**
@@ -130,6 +153,7 @@ HttpRequest buildTokenRequest(Map<String, String> parameters) {
130153
return HttpRequest.newBuilder(tokenEndpoint) //
131154
.header("Content-Type", "application/x-www-form-urlencoded") //
132155
.POST(HttpRequest.BodyPublishers.ofString(urlencodedParams)) //
156+
.timeout(requestTimeout) //
133157
.build();
134158
}
135159

src/test/java/io/github/coffeelibs/tinyoauth2client/AuthFlowTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ public void setup() throws IOException {
201201
authFlow = new AuthFlow(client, authEndpoint, pkce);
202202
redirectTarget = Mockito.mock(RedirectTarget.class);
203203
redirectTargetClass = Mockito.mockStatic(RedirectTarget.class);
204-
redirectTargetClass.when(() -> RedirectTarget.start(Mockito.any(), Mockito.any())).thenReturn(redirectTarget);
204+
redirectTargetClass.when(() -> RedirectTarget.start(Mockito.any(), Mockito.any(int[].class))).thenReturn(redirectTarget);
205205
browser = Mockito.mock(Consumer.class);
206206

207207
var redirected = new CountDownLatch(1);
@@ -351,7 +351,7 @@ public void testAuthorizeAsync() throws IOException, ExecutionException, Interru
351351
var authFlow = Mockito.spy(new AuthFlow(client, authEndpoint, pkce));
352352
var authFlowWithCode = Mockito.mock(AuthFlow.AuthFlowWithCode.class);
353353
var httpResponse = Mockito.mock(HttpResponse.class);
354-
Mockito.doReturn(authFlowWithCode).when(authFlow).requestAuthCode(Mockito.any(), Mockito.any());
354+
Mockito.doReturn(authFlowWithCode).when(authFlow).requestAuthCode(Mockito.any());
355355
Mockito.doReturn(CompletableFuture.completedFuture(httpResponse)).when(authFlowWithCode).getAccessTokenAsync((HttpClient) Mockito.any());
356356

357357
var result = authFlow.authorizeAsync(httpClient, browser);
@@ -363,7 +363,7 @@ public void testAuthorizeAsync() throws IOException, ExecutionException, Interru
363363
@Test
364364
@DisplayName("authorizeAsync(executor, ...) delegates to authorizeAsync(httpClient,...) with executor set in httpClient")
365365
@SuppressWarnings("unchecked")
366-
public void testAuthorizeAsync2() throws IOException, ExecutionException, InterruptedException {
366+
public void testAuthorizeAsync2() {
367367
var executor = Mockito.mock(Executor.class);
368368
Consumer<URI> browser = Mockito.mock(Consumer.class);
369369
var authFlow = Mockito.spy(new AuthFlow(client, authEndpoint, pkce));
@@ -382,7 +382,7 @@ public void testAuthorizeAsyncWithError1() throws IOException {
382382
Consumer<URI> browser = Mockito.mock(Consumer.class);
383383
//var executor = Mockito.mock(Executor.class);
384384
var authFlow = Mockito.spy(new AuthFlow(client, authEndpoint, pkce));
385-
Mockito.doThrow(new IOException("error")).when(authFlow).requestAuthCode(Mockito.any(), Mockito.any());
385+
Mockito.doThrow(new IOException("error")).when(authFlow).requestAuthCode(Mockito.any());
386386

387387
var result = authFlow.authorizeAsync(Runnable::run, browser);
388388

@@ -397,7 +397,7 @@ public void testAuthorizeAsyncWithError2() throws IOException {
397397
//var executor = Mockito.mock(Executor.class);
398398
var authFlow = Mockito.spy(new AuthFlow(client, authEndpoint, pkce));
399399
var authFlowWithCode = Mockito.mock(AuthFlow.AuthFlowWithCode.class);
400-
Mockito.doReturn(authFlowWithCode).when(authFlow).requestAuthCode(Mockito.any(), Mockito.any());
400+
Mockito.doReturn(authFlowWithCode).when(authFlow).requestAuthCode(Mockito.any());
401401

402402
var result = authFlow.authorizeAsync(Runnable::run, browser);
403403

@@ -413,7 +413,7 @@ public void testAuthorize() throws IOException, InterruptedException {
413413
var authFlow = Mockito.spy(new AuthFlow(client, authEndpoint, pkce));
414414
var authFlowWithCode = Mockito.mock(AuthFlow.AuthFlowWithCode.class);
415415
var httpResponse = Mockito.mock(HttpResponse.class);
416-
Mockito.doReturn(authFlowWithCode).when(authFlow).requestAuthCode(Mockito.any(), Mockito.any());
416+
Mockito.doReturn(authFlowWithCode).when(authFlow).requestAuthCode(Mockito.any());
417417
Mockito.doReturn(httpResponse).when(authFlowWithCode).getAccessToken(httpClient);
418418

419419
var result = authFlow.authorize(httpClient, browser);

src/test/java/io/github/coffeelibs/tinyoauth2client/TinyOAuth2ClientTest.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.net.http.HttpClient;
1212
import java.net.http.HttpRequest;
1313
import java.net.http.HttpResponse;
14+
import java.time.Duration;
1415
import java.util.Map;
1516
import java.util.concurrent.CompletableFuture;
1617
import java.util.concurrent.ExecutionException;
@@ -31,9 +32,21 @@ public void testAuthFlow() {
3132
Assertions.assertNotNull(authFlow.pkce);
3233
}
3334

35+
@Test
36+
@DisplayName("withRequestTimeout(...)")
37+
public void testWithRequestTimeout() {
38+
var client = new TinyOAuth2Client("my-client", URI.create("http://example.com/oauth2/token"));
39+
var timeout = Duration.ofMillis(1337L);
40+
41+
var newClient = client.withRequestTimeout(timeout);
42+
43+
Assertions.assertNotSame(client, newClient);
44+
Assertions.assertEquals(timeout, newClient.requestTimeout);
45+
}
46+
3447
@Test
3548
@DisplayName("refreshAsync(executor, \"r3fr3sh70k3n\") sends refresh token request")
36-
public void testRefreshAsync() throws ExecutionException {
49+
public void testRefreshAsync() {
3750
var tokenEndpoint = URI.create("http://example.com/oauth2/token");
3851
var client = Mockito.spy(new TinyOAuth2Client("my-client", tokenEndpoint));
3952
var executor = Mockito.mock(Executor.class);
@@ -59,7 +72,7 @@ public void testRefreshAsync() throws ExecutionException {
5972

6073
@Test
6174
@DisplayName("refreshAsync(executor, \"r3fr3sh70k3n\", \"foo\", \"bar\") sends refresh token request")
62-
public void testRefreshAsyncWithScopes() throws ExecutionException {
75+
public void testRefreshAsyncWithScopes() {
6376
var tokenEndpoint = URI.create("http://example.com/oauth2/token");
6477
var client = Mockito.spy(new TinyOAuth2Client("my-client", tokenEndpoint));
6578
var executor = Mockito.mock(Executor.class);
@@ -71,7 +84,7 @@ public void testRefreshAsyncWithScopes() throws ExecutionException {
7184
httpClientClass.when(HttpClient::newBuilder).thenReturn(httpClientBuilder);
7285
Mockito.doReturn(httpClient).when(httpClientBuilder).build();
7386
Mockito.doReturn(httpClientBuilder).when(httpClientBuilder).executor(Mockito.any());
74-
Mockito.doReturn(httpRequest).when(client).buildRefreshTokenRequest(Mockito.any(), Mockito.any());
87+
Mockito.doReturn(httpRequest).when(client).buildRefreshTokenRequest("r3fr3sh70k3n", "foo", "bar");
7588
Mockito.doReturn(CompletableFuture.completedFuture(httpRespone)).when(httpClient).sendAsync(Mockito.any(), Mockito.any());
7689

7790
var result = client.refreshAsync(executor, "r3fr3sh70k3n", "foo", "bar");
@@ -93,7 +106,7 @@ public void testRefresh() throws IOException, InterruptedException {
93106
var httpRespone = Mockito.mock(HttpResponse.class);
94107
try (var httpClientClass = Mockito.mockStatic(HttpClient.class)) {
95108
httpClientClass.when(HttpClient::newHttpClient).thenReturn(httpClient);
96-
Mockito.doReturn(httpRequest).when(client).buildRefreshTokenRequest(Mockito.any());
109+
Mockito.doReturn(httpRequest).when(client).buildRefreshTokenRequest("r3fr3sh70k3n");
97110
Mockito.doReturn(httpRespone).when(httpClient).send(Mockito.any(), Mockito.any());
98111

99112
var result = client.refresh("r3fr3sh70k3n");
@@ -114,7 +127,7 @@ public void testRefreshWithScopes() throws IOException, InterruptedException {
114127
var httpRespone = Mockito.mock(HttpResponse.class);
115128
try (var httpClientClass = Mockito.mockStatic(HttpClient.class)) {
116129
httpClientClass.when(HttpClient::newHttpClient).thenReturn(httpClient);
117-
Mockito.doReturn(httpRequest).when(client).buildRefreshTokenRequest(Mockito.any(), Mockito.any());
130+
Mockito.doReturn(httpRequest).when(client).buildRefreshTokenRequest("r3fr3sh70k3n", "foo", "bar");
118131
Mockito.doReturn(httpRespone).when(httpClient).send(Mockito.any(), Mockito.any());
119132

120133
var result = client.refresh("r3fr3sh70k3n", "foo", "bar");
@@ -181,6 +194,7 @@ public void testBuildTokenRequest() {
181194
bodyPublishersClass.verify(() -> HttpRequest.BodyPublishers.ofString("query=string&mock=true"));
182195
Assertions.assertEquals(tokenEndpoint, request.uri());
183196
Assertions.assertEquals("POST", request.method());
197+
Assertions.assertEquals(client.requestTimeout, request.timeout().get());
184198
Assertions.assertEquals(bodyPublisher, request.bodyPublisher().get());
185199
Assertions.assertEquals("application/x-www-form-urlencoded", request.headers().firstValue("Content-Type").orElse(null));
186200
}

src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)