Skip to content
This repository was archived by the owner on Jul 3, 2020. It is now read-only.

Commit d7a9232

Browse files
author
Florian Wallner
committed
Merge pull request #178 from tkrille/legacy-mode
Restore support for OSIAM 2.x
2 parents 9727e33 + 03c669f commit d7a9232

File tree

10 files changed

+483
-107
lines changed

10 files changed

+483
-107
lines changed

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,21 @@
22

33
## 1.8 - Unreleased
44

5-
### Changes
5+
### Features
66

77
- Ability to set timeouts on per connector basis
88
- Add client management
9+
- Add legacy schemas mode for connecting to OSIAM <= 2.3
10+
11+
Please, see [Create an OSIAM connector](docs/create-osiam-connector.md#legacy-schemas),
12+
if you use an OSIAM version <= 2.3.
13+
14+
- Restore support for OSIAM 2.x
15+
16+
### Changes
17+
18+
- `OsiamConnector#setMaxConnections(int maxConnections)` will also set
19+
the maximum connections per route to the given value.
920

1021
## 1.7 - 2015-09-11
1122

docs/create-osiam-connector.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,55 @@ To be able to log in, and create or change users or groups you need to create
22
an `org.osiam.client.connector.OsiamConnector` instance. You can do this by
33
using the `OsiamConnector.Builder()` class.
44

5+
## OSIAM 3.x
6+
7+
In OSIAM 3.x auth-server and resource-server have been merged to create a better
8+
user experience. Thus you have to provide only 1 endpoint for the Connector to
9+
connect to OSIAM:
10+
11+
512
```java
613
OsiamConnector osiamConnector = new OsiamConnector.Builder()
7-
.setEndpoint(OSIAM_ENDPOINT)
14+
.withEndpoint(OSIAM_ENDPOINT)
815
.setClientId(CLIENT_ID)
916
.setClientSecret(CLIENT_SECRET)
1017
.build();
1118
```
1219

20+
## OSIAM 2.x
21+
22+
OSIAM consists of 2 servers, namely auth-server and resource-server. Therefore
23+
you have to provide 2 endpoints for the Connector to connect to OSIAM:
24+
25+
```java
26+
OsiamConnector osiamConnector = new OsiamConnector.Builder()
27+
.setAuthServerEndpoint(AUTH_ENDPOINT_ADDRESS)
28+
.setResourceServerEndpoint(RESOURCE_ENDPOINT_ADDRESS)
29+
.setClientId(CLIENT_ID)
30+
.setClientSecret(CLIENT_SECRET)
31+
.build();
32+
```
33+
34+
In case your auth and resource server are located at the same location and
35+
follow the specified naming convention you can also use:
36+
37+
```java
38+
OsiamConnector osiamConnector = new OsiamConnector.Builder()
39+
.setEndpoint(OSIAM_ENDPOINT)
40+
.setClientId(CLIENT_ID)
41+
.setClientSecret(CLIENT_SECRET)
42+
.build();
43+
```
44+
45+
This will append the default context roots to the given endpoint:
46+
47+
- auth-server: `/osiam-auth-server`
48+
- resource-server: `/osiam-resource-server`
49+
1350
## Timeouts
1451

15-
(since 1.4) You can also set the connect and read timeouts like this:
52+
Starting with version 1.4 you can also set the connect and read timeouts
53+
like this:
1654

1755
```java
1856
OsiamConnector.setConnectTimeout(2500);
@@ -24,3 +62,20 @@ define them for **all** connectors you create. This will be addressed in a
2462
future version, but note that it is recommended to use only **one** connector
2563
instance for the whole application, unless you need to use different OAuth
2664
clients.
65+
66+
## Legacy Schemas
67+
68+
Starting with version 1.8 you can configure the use of legacy schemas, i.e.
69+
schemas that were defined before SCIM 2 draft 09, like this:
70+
71+
```java
72+
OsiamConnector osiamConnector = new OsiamConnector.Builder()
73+
...
74+
.withLegacySchemas(true)
75+
...
76+
.build();
77+
```
78+
79+
This enables compatibility with OSIAM releases up to version 2.3 (resource-server 2.2). This
80+
behavior is not enabled by default. Set it to `true` if you connect to an OSIAM version <= 2.3 and,
81+
please, update to 2.5 or later immediately.

docs/login-and-getting-an-access-token.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ With **new Scope("your scope");** you can also create and add your own scopes th
2626
# Retrieving an access token
2727

2828
In a trusted environment getting an access token from OSIAM implies a successful
29-
login of the user.
29+
login of the user.
3030

3131
## [Authorization Code Grant](https://github.com/osiam/osiam/blob/master/docs/api_documentation.md#authorization-code-grant)
3232

@@ -73,7 +73,7 @@ AccessToken the following way
7373

7474
AccessToken accessToken = new AccessToken.Builder(<token>).build();
7575

76-
## [Resource Owner Password Credentials Grant](https://github.com/osiam/osiam/blob/master/docs/api_documentation.md#resource-owner-password-credentials-grant)
76+
## [Resource Owner Password Credentials Grant](https://github.com/osiam/osiam/blob/master/docs/api_documentation.md#resource-owner-password-credentials-grant)
7777
and
7878
## [Client Credentials Grant](https://github.com/osiam/osiam/blob/master/docs/api_documentation.md#client-credentials-grant)
7979

docs/vertx-example.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ public class Main {
2626

2727
{
2828
oConnector = new OsiamConnector.Builder()
29-
.setEndpoint("http://localhost:8180/osiam")
29+
// OSIAM 3.x
30+
.withEndpoint("http://localhost:8080/osiam")
31+
// OSIAM 2.x
32+
.setEndpoint("http://localhost:8080")
3033
.setClientId("example-client")
3134
.setClientSecret("secret")
3235
.setClientRedirectUri("http://localhost:5000/oauth2")

src/main/java/org/osiam/client/AbstractOsiamService.java

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,17 @@
2828
import com.fasterxml.jackson.core.type.TypeReference;
2929
import com.fasterxml.jackson.databind.JavaType;
3030
import com.fasterxml.jackson.databind.module.SimpleModule;
31+
import com.fasterxml.jackson.databind.node.ArrayNode;
32+
import com.fasterxml.jackson.databind.node.ObjectNode;
3133
import com.fasterxml.jackson.databind.type.TypeFactory;
3234
import com.google.common.base.Strings;
3335
import org.glassfish.jersey.client.ClientProperties;
34-
import org.osiam.client.exception.ConflictException;
35-
import org.osiam.client.exception.ConnectionInitializationException;
36-
import org.osiam.client.exception.ForbiddenException;
37-
import org.osiam.client.exception.NoResultException;
38-
import org.osiam.client.exception.OAuthErrorMessage;
39-
import org.osiam.client.exception.OsiamClientException;
40-
import org.osiam.client.exception.OsiamRequestException;
41-
import org.osiam.client.exception.UnauthorizedException;
36+
import org.osiam.client.exception.*;
4237
import org.osiam.client.oauth.AccessToken;
4338
import org.osiam.client.query.Query;
4439
import org.osiam.client.query.QueryBuilder;
4540
import org.osiam.resources.helper.UserDeserializer;
46-
import org.osiam.resources.scim.ErrorResponse;
47-
import org.osiam.resources.scim.Resource;
48-
import org.osiam.resources.scim.SCIMSearchResult;
49-
import org.osiam.resources.scim.User;
41+
import org.osiam.resources.scim.*;
5042

5143
import javax.ws.rs.ProcessingException;
5244
import javax.ws.rs.client.Entity;
@@ -80,6 +72,7 @@ abstract class AbstractOsiamService<T extends Resource> {
8072
private final String typeName;
8173
private final int connectTimeout;
8274
private final int readTimeout;
75+
private final boolean legacySchemas;
8376

8477
protected final WebTarget targetEndpoint;
8578

@@ -88,9 +81,12 @@ protected AbstractOsiamService(Builder<T> builder) {
8881
typeName = builder.typeName;
8982
connectTimeout = builder.connectTimeout;
9083
readTimeout = builder.readTimeout;
84+
legacySchemas = builder.legacySchemas;
9185

86+
UserDeserializer userDeserializer =
87+
legacySchemas ? new UserDeserializer(OsiamUserService.LEGACY_SCHEMA) : new UserDeserializer();
9288
SimpleModule userDeserializerModule = new SimpleModule("userDeserializerModule", Version.unknownVersion())
93-
.addDeserializer(User.class, new UserDeserializer(User.class));
89+
.addDeserializer(User.class, userDeserializer);
9490
objectMapper.registerModule(userDeserializerModule);
9591

9692
targetEndpoint = OsiamConnector.getClient().target(builder.endpoint);
@@ -192,8 +188,8 @@ protected T createResource(T resource, AccessToken accessToken) {
192188

193189
String resourceAsString;
194190
try {
195-
resourceAsString = objectMapper.writeValueAsString(resource);
196-
} catch (JsonProcessingException e) {
191+
resourceAsString = mapToString(resource);
192+
} catch (JsonProcessingException | ClassCastException e) {
197193
throw new ConnectionInitializationException(CONNECTION_SETUP_ERROR_STRING, e);
198194
}
199195

@@ -232,7 +228,7 @@ private T modifyResource(String id, T resource, String method, AccessToken acces
232228

233229
String resourceAsString;
234230
try {
235-
resourceAsString = objectMapper.writeValueAsString(resource);
231+
resourceAsString = mapToString(resource);
236232
} catch (JsonProcessingException e) {
237233
throw new ConnectionInitializationException(CONNECTION_SETUP_ERROR_STRING, e);
238234
}
@@ -257,18 +253,48 @@ private T modifyResource(String id, T resource, String method, AccessToken acces
257253
return mapToResource(content);
258254
}
259255

260-
protected T mapToResource(String content) {
256+
private T mapToResource(String content) {
261257
return mapToType(content, type);
262258
}
263259

264260
protected <U> U mapToType(String content, Class<U> type) {
265261
try {
266-
return objectMapper.readValue(content, type);
267-
} catch (IOException e) {
262+
if (legacySchemas && (type == User.class || type == Group.class)) {
263+
ObjectNode resourceNode = (ObjectNode) objectMapper.readTree(content);
264+
switchToLegacySchema(resourceNode);
265+
return objectMapper.readValue(objectMapper.treeAsTokens(resourceNode), type);
266+
} else {
267+
return objectMapper.readValue(content, type);
268+
}
269+
} catch (IOException | ClassCastException e) {
268270
throw new OsiamClientException(String.format("Unable to parse %s: %s", typeName, content), e);
269271
}
270272
}
271273

274+
private String mapToString(T resource) throws JsonProcessingException {
275+
if (legacySchemas) {
276+
ObjectNode resourceNode = objectMapper.valueToTree(resource);
277+
switchToLegacySchema(resourceNode);
278+
return resourceNode.toString();
279+
} else {
280+
return objectMapper.writeValueAsString(resource);
281+
}
282+
}
283+
284+
private void switchToLegacySchema(ObjectNode resourceNode) {
285+
ArrayNode schemas = (ArrayNode) resourceNode.get("schemas");
286+
for (int i = 0; i < schemas.size(); i++) {
287+
if (getSchema().equals(schemas.get(i).textValue())) {
288+
schemas.remove(i);
289+
}
290+
}
291+
schemas.add(getLegacySchema());
292+
}
293+
294+
protected abstract String getSchema();
295+
296+
protected abstract String getLegacySchema();
297+
272298
protected void checkAndHandleResponse(String content, StatusType status, AccessToken accessToken) {
273299
if (status.getFamily() == Family.SUCCESSFUL) {
274300
return;
@@ -309,25 +335,29 @@ protected String extractErrorMessageDefault(String content, StatusType status) {
309335
}
310336

311337
protected String extractErrorMessage(String content, StatusType status) {
312-
313-
String message = getScimErrorMessageSinceOsiam3(content);
314-
if (message == null) {
315-
message = getScimErrorMessageUpToOsiam2(content);
338+
String message;
339+
if (legacySchemas) {
340+
message = getScimErrorMessageLegacy(content);
341+
} else {
342+
message = getScimErrorMessage(content);
316343
}
344+
317345
if (message == null) {
318346
message = getOAuthErrorMessage(content);
319347
}
348+
320349
if (message == null) {
321350
message = String.format("Could not deserialize the error response for the HTTP status '%s'.",
322351
status.getReasonPhrase());
323352
if (content != null) {
324353
message += String.format(" Original response: %s", content);
325354
}
326355
}
356+
327357
return message;
328358
}
329359

330-
private String getScimErrorMessageSinceOsiam3(String content) {
360+
private String getScimErrorMessage(String content) {
331361
try {
332362
ErrorResponse error = objectMapper.readValue(content, ErrorResponse.class);
333363
return error.getDetail();
@@ -336,7 +366,7 @@ private String getScimErrorMessageSinceOsiam3(String content) {
336366
}
337367
}
338368

339-
private String getScimErrorMessageUpToOsiam2(String content) {
369+
private String getScimErrorMessageLegacy(String content) {
340370
try {
341371
Map<String, String> error = objectMapper.readValue(content, new TypeReference<Map<String, String>>() {
342372
});
@@ -374,6 +404,7 @@ protected static class Builder<T> {
374404
private String typeName;
375405
protected int connectTimeout = OsiamConnector.DEFAULT_CONNECT_TIMEOUT;
376406
protected int readTimeout = OsiamConnector.DEFAULT_READ_TIMEOUT;
407+
protected boolean legacySchemas = OsiamConnector.DEFAULT_LEGACY_SCHEMAS;
377408

378409
@SuppressWarnings("unchecked")
379410
protected Builder(String endpoint) {

0 commit comments

Comments
 (0)