Skip to content

Commit 3e3872a

Browse files
Merge pull request #70 from privacyidea/69-reuse-saved-jwt-auth-token-until-it-expire-1
69 reuse saved jwt auth token until it expire 1
2 parents bb42f5d + 3d50f1f commit 3e3872a

16 files changed

+345
-144
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ jobs:
1414
runs-on: ubuntu-latest
1515

1616
steps:
17-
- uses: actions/checkout@v3
17+
- uses: actions/checkout@v4
1818

1919
- name: Setup Java Development Kits
20-
uses: actions/setup-java@v3
20+
uses: actions/setup-java@v4
2121
with:
2222
java-version: 17
2323
distribution: microsoft

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,10 @@
115115
<version>2.0.5</version>
116116
<scope>test</scope>
117117
</dependency>
118+
<dependency>
119+
<groupId>com.auth0</groupId>
120+
<artifactId>java-jwt</artifactId>
121+
<version>4.4.0</version>
122+
</dependency>
118123
</dependencies>
119124
</project>

src/main/java/org/privacyidea/AsyncRequestCallable.java

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.jetbrains.annotations.NotNull;
2323

2424
import java.io.IOException;
25-
import java.util.Collections;
2625
import java.util.Map;
2726
import java.util.concurrent.Callable;
2827
import java.util.concurrent.CountDownLatch;
@@ -35,7 +34,7 @@
3534
*/
3635
public class AsyncRequestCallable implements Callable<String>, Callback
3736
{
38-
private String path;
37+
private final String path;
3938
private final String method;
4039
private final Map<String, String> headers;
4140
private final Map<String, String> params;
@@ -63,32 +62,8 @@ public String call() throws Exception
6362
// If an auth token is required for the request, get that first then do the actual request
6463
if (this.authTokenRequired)
6564
{
66-
if (!privacyIDEA.serviceAccountAvailable())
67-
{
68-
privacyIDEA.error("Service account is required to retrieve auth token!");
69-
return null;
70-
}
71-
latch = new CountDownLatch(1);
72-
String tmpPath = path;
73-
path = ENDPOINT_AUTH;
74-
endpoint.sendRequestAsync(ENDPOINT_AUTH, privacyIDEA.serviceAccountParam(), Collections.emptyMap(), PIConstants.POST, this);
75-
if (!latch.await(30, TimeUnit.SECONDS))
76-
{
77-
privacyIDEA.error("Latch timed out...");
78-
return "";
79-
}
80-
// Extract the auth token from the response
81-
String response = callbackResult[0];
82-
String authToken = privacyIDEA.parser.extractAuthToken(response);
83-
if (authToken == null)
84-
{
85-
// The parser already logs the error.
86-
return null;
87-
}
88-
// Add the auth token to the header
89-
headers.put(PIConstants.HEADER_AUTHORIZATION, authToken);
90-
path = tmpPath;
91-
callbackResult[0] = null;
65+
// Wait for the auth token to be retrieved and add it to the header
66+
headers.put(PIConstants.HEADER_AUTHORIZATION, privacyIDEA.getJWT());
9267
}
9368

9469
// Do the actual request

src/main/java/org/privacyidea/Endpoint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
/**
3838
* This class handles sending requests to the server.
3939
*/
40-
class Endpoint
40+
public class Endpoint
4141
{
4242
private final PrivacyIDEA privacyIDEA;
4343
private final PIConfig piConfig;

src/main/java/org/privacyidea/JSONParser.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@
1818

1919
import com.google.gson.*;
2020

21-
import java.util.ArrayList;
22-
import java.util.LinkedHashMap;
23-
import java.util.List;
24-
import java.util.Map;
21+
import java.util.*;
2522

2623
import static org.privacyidea.PIConstants.*;
2724

@@ -66,9 +63,9 @@ public String formatJson(String json)
6663
* Extract the auth token from the response of the server.
6764
*
6865
* @param serverResponse response of the server
69-
* @return the auth token or null if error
66+
* @return the AuthToken obj or null if error
7067
*/
71-
String extractAuthToken(String serverResponse)
68+
LinkedHashMap<String, String> extractAuthToken(String serverResponse)
7269
{
7370
if (serverResponse != null && !serverResponse.isEmpty())
7471
{
@@ -78,11 +75,21 @@ String extractAuthToken(String serverResponse)
7875
try
7976
{
8077
JsonObject obj = root.getAsJsonObject();
81-
return obj.getAsJsonObject(RESULT).getAsJsonObject(VALUE).getAsJsonPrimitive(TOKEN).getAsString();
78+
String authToken = obj.getAsJsonObject(RESULT).getAsJsonObject(VALUE).getAsJsonPrimitive(TOKEN).getAsString();
79+
var parts = authToken.split("\\.");
80+
String dec = new String(Base64.getDecoder().decode(parts[1]));
81+
82+
// Extract the expiration date from the token
83+
int respDate = obj.getAsJsonPrimitive(TIME).getAsInt();
84+
int expDate = JsonParser.parseString(dec).getAsJsonObject().getAsJsonPrimitive(EXP).getAsInt();
85+
int difference = expDate - respDate;
86+
privacyIDEA.log("JWT Validity: " + difference / 60 + " minutes. Token expires at: " + new Date(expDate * 1000L));
87+
88+
return new LinkedHashMap<>(Map.of(AUTH_TOKEN, authToken, AUTH_TOKEN_EXP, String.valueOf(expDate)));
8289
}
8390
catch (Exception e)
8491
{
85-
privacyIDEA.error("Response did not contain an authorization token: " + formatJson(serverResponse));
92+
privacyIDEA.error("Auth token extraction failed: " + e);
8693
}
8794
}
8895
}
@@ -232,7 +239,7 @@ else if ("interactive".equals(modeFromResponse))
232239

233240
if (TOKEN_TYPE_WEBAUTHN.equals(type))
234241
{
235-
String webauthnSignRequest = getItemFromAttributes(WEBAUTHN_SIGN_REQUEST, challenge);
242+
String webauthnSignRequest = getItemFromAttributes(challenge);
236243
response.multiChallenge.add(new WebAuthn(serial, message, clientMode, image, transactionID, webauthnSignRequest));
237244
}
238245
else
@@ -263,13 +270,13 @@ static String mergeWebAuthnSignRequest(WebAuthn webauthn, List<String> arr) thro
263270
return signRequest.toString();
264271
}
265272

266-
private String getItemFromAttributes(String item, JsonObject jsonObject)
273+
private String getItemFromAttributes(JsonObject jsonObject)
267274
{
268275
String ret = "";
269276
JsonElement attributeElement = jsonObject.get(ATTRIBUTES);
270277
if (attributeElement != null && !attributeElement.isJsonNull())
271278
{
272-
JsonElement requestElement = attributeElement.getAsJsonObject().get(item);
279+
JsonElement requestElement = attributeElement.getAsJsonObject().get(PIConstants.WEBAUTHN_SIGN_REQUEST);
273280
if (requestElement != null && !requestElement.isJsonNull())
274281
{
275282
ret = requestElement.toString();

src/main/java/org/privacyidea/PIConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ public class PIConstants
4848
public static final String PASSWORD = "password";
4949
public static final String PASS = "pass";
5050
public static final String SERIAL = "serial";
51+
public static final String TIME = "time";
52+
public static final String EXP = "exp";
5153
public static final String CHALLENGE_STATUS = "challenge_status";
54+
public static final String AUTH_TOKEN = "authToken";
55+
public static final String AUTH_TOKEN_EXP = "authTokenExp";
5256
public static final String TYPE = "type";
5357
public static final String TRANSACTION_ID = "transaction_id";
5458
public static final String REALM = "realm";

src/main/java/org/privacyidea/PIResponse.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
import java.util.function.Predicate;
2424
import java.util.stream.Collectors;
2525

26-
import static org.privacyidea.PIConstants.*;
26+
import static org.privacyidea.PIConstants.TOKEN_TYPE_PUSH;
27+
import static org.privacyidea.PIConstants.TOKEN_TYPE_WEBAUTHN;
2728

2829
/**
2930
* This class parses the JSON response of privacyIDEA into a POJO for easier access.

0 commit comments

Comments
 (0)