Skip to content

Commit

Permalink
Revert RoutingContext#user() returning UserContext to User.
Browse files Browse the repository at this point in the history
Motivation:

RoutingContext#user() method returns the io.vertx.ext.auth.User interface in Vert.x 4.x, its return type has been change to UserContext instead (in addition of other changes), as UserContext is the preferred API for interacting with the user and the User interface actually represents the User.

However, there is nothing wrong with having the user method returns the io.vertx.ext.auth.User interface, since the User interface is still the API for accessing user informations. The UserContext API can be returned from a userContext method instead. This avoids breaking the contract of the user method between 4.x and 5.0

Changes:

Introduce a new userContext method returning the UserContext and change the return type of the user method to return the User type.
  • Loading branch information
vietj committed Dec 16, 2024
1 parent 7367748 commit 0a830cf
Show file tree
Hide file tree
Showing 38 changed files with 125 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public OpenAPIRouterHandlerImpl(EventBus eventBus, String address, DeliveryOptio
protected Future<JsonObject> transformRequest(ValidatedRequest request, RoutingContext routingContext,
Operation operation) {
JsonObject params = buildParametersObject(request);
JsonObject userPrincipal = Optional.ofNullable(routingContext.user().get()).map(User::principal).orElse(null);
JsonObject userPrincipal = Optional.ofNullable(routingContext.user()).map(User::principal).orElse(null);

ServiceRequest sr = new ServiceRequest(
params,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public RouteToEBServiceHandlerImpl extraPayloadMapper(Function<RoutingContext, J

private JsonObject buildPayload(RoutingContext context) {
JsonObject params = context.get("parsedParameters") != null ? ((RequestParameters)context.get("parsedParameters")).toJson() : null;
User user = context.user().get();
User user = context.user();
return new JsonObject().put("context", new ServiceRequest(
params,
context.request().headers(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public void authorizedUserTest(Vertx vertx, VertxTestContext testContext) {
.handler(
ValidationHandlerBuilder.create(schemaRepo).build()
).handler(rc -> {
((UserContextInternal) rc.user()).setUser(User.fromName("slinkydeveloper")); // Put user mock into context
((UserContextInternal) rc.userContext()).setUser(User.fromName("slinkydeveloper")); // Put user mock into context
rc.next();
})
.handler(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void routingContextInDataFetchingEnvironment() {

RoutingContext routingContext = environment.getGraphQlContext().get(RoutingContext.class);

UserContext user = routingContext.user();
UserContext user = routingContext.userContext();

Future<List<Link>> future = retrieveLinksPostedBy(user);
return future.toCompletionStage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ void testBuilderWithAuthn(VertxTestContext testContext) {
.onSuccess(self -> {
self
.getRoute("opA")
.addHandler(ctx -> ctx.json(ctx.user().get().principal()));
.addHandler(ctx -> ctx.json(ctx.user().principal()));
self
.getRoute("opB")
.addHandler(ctx -> ctx.json(ctx.user().get().principal()));
.addHandler(ctx -> ctx.json(ctx.user().principal()));
}))
// this test may seem useless but it proves that the chain auth properly sets up a chain when the a handler
// can perform redirects (callback aware) and doesn't throw an exception at setup time.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ void testBuilderWithAuthn(VertxTestContext testContext) {

rb.getRoute("pets")
.addHandler(ctx -> {
if (ctx.user().authenticated()) {
ctx.json(ctx.user().get().principal());
if (ctx.userContext().authenticated()) {
ctx.json(ctx.user().principal());
} else {
ctx.json(null);
}
Expand Down
2 changes: 1 addition & 1 deletion vertx-web/src/main/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,7 @@ make sure your authentication handler is before your application handlers on tho

If the authentication handler has successfully authenticated the user it will inject a {@link io.vertx.ext.auth.User}
object into the {@link io.vertx.ext.web.UserContext} so it's available in your handlers from the routing context:
{@link io.vertx.ext.web.RoutingContext#user()}.
{@link io.vertx.ext.web.RoutingContext#userContext()}.

If you want your User object to be stored in the session so it's available between requests so you don't have to
authenticate on each request, then you should make sure you have a session handler before the authentication handler.
Expand Down
17 changes: 8 additions & 9 deletions vertx-web/src/main/java/examples/WebExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import io.vertx.ext.web.sstore.SessionStore;

import java.util.List;
import java.util.function.Function;

/**
* These are the examples used in the documentation.
Expand Down Expand Up @@ -837,7 +836,7 @@ public void example38(Vertx vertx, AuthenticationProvider authProvider, Router r
// This will require a login

// This will have the value true
boolean isAuthenticated = ctx.user().authenticated();
boolean isAuthenticated = ctx.userContext().authenticated();

});
}
Expand Down Expand Up @@ -871,7 +870,7 @@ public void example39(Vertx vertx, AuthenticationProvider authProvider, Router r
// This will require a login

// This will have the value true
boolean isAuthenticated = ctx.user().authenticated();
boolean isAuthenticated = ctx.userContext().authenticated();

});

Expand Down Expand Up @@ -1268,8 +1267,8 @@ public void example52(Vertx vertx) {
public void example53(Vertx vertx) {

Handler<RoutingContext> handler = ctx -> {
String theSubject = ctx.user().get().principal().getString("sub");
String someKey = ctx.user().get().principal().getString("someKey");
String theSubject = ctx.user().principal().getString("sub");
String someKey = ctx.user().principal().getString("someKey");
};
}

Expand Down Expand Up @@ -1495,7 +1494,7 @@ public void example62(Vertx vertx, Router router) {
// at this moment your user object should contain the info
// from the Oauth2 response, since this is a protected resource
// as specified above in the handler config the user object is never null
User user = ctx.user().get();
User user = ctx.user();
// just dump it to the client for demo purposes
ctx.response().end(user.toString());
});
Expand Down Expand Up @@ -1947,7 +1946,7 @@ public void example89(Router router) {
.handler(ctx -> {
// if the user isn't admin, we ask the user to login again as admin
ctx
.user()
.userContext()
.loginHint("admin")
.impersonate();
});
Expand All @@ -1958,7 +1957,7 @@ public void example90(Router router) {
.route("/high/security/route/back/to/me")
.handler(ctx -> {
ctx
.user()
.userContext()
.restore();
});
}
Expand All @@ -1968,7 +1967,7 @@ public void example91(Router router) {
.route("/high/security/route/refresh/me")
.handler(ctx -> {
ctx
.user()
.userContext()
.refresh();
});
}
Expand Down
11 changes: 10 additions & 1 deletion vertx-web/src/main/java/io/vertx/ext/web/RoutingContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.vertx.core.internal.ContextInternal;
import io.vertx.core.json.EncodeException;
import io.vertx.core.json.Json;
import io.vertx.ext.auth.User;
import io.vertx.ext.web.impl.ParsableMIMEValue;
import io.vertx.ext.web.impl.Utils;

Expand Down Expand Up @@ -223,7 +224,15 @@ public interface RoutingContext {
* as perform authentication refreshes, logout and other operations.
* @return the user context
*/
UserContext user();
UserContext userContext();

/**
* Get the authenticated user (if any). This will usually be injected by an auth handler if authentication if successful.
* @return the user, or null if the current user is not authenticated.
*/
default @Nullable User user() {
return userContext().get();
}

/**
* If the context is being routed to failure handlers after a failure has been triggered by calling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void handle(RoutingContext ctx) {
ctx.request().pause();
}

final User user = ctx.user().get();
final User user = ctx.user();

if (user != null) {
if (mfa != null) {
Expand All @@ -85,7 +85,7 @@ public void handle(RoutingContext ctx) {
// perform the authentication
authenticate(ctx)
.onSuccess(authenticated -> {
((UserContextInternal) ctx.user())
((UserContextInternal) ctx.userContext())
.setUser(authenticated);
Session session = ctx.session();
if (session != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private Authorization computeAuthorizationIfNeeded(RoutingContext ctx) {

@Override
public void handle(RoutingContext ctx) {
final User user = ctx.user().get();
final User user = ctx.user();

if (user == null) {
ctx.fail(FORBIDDEN_CODE, FORBIDDEN_EXCEPTION);
Expand Down Expand Up @@ -141,7 +141,7 @@ public AuthorizationHandler variableConsumer(BiConsumer<RoutingContext, Authoriz
* @param providers the providers iterator
*/
private void checkOrFetchAuthorizations(RoutingContext ctx, Authorization authorization, AuthorizationContext authorizationContext, Iterator<AuthorizationProvider> providers) {
final User user = ctx.user().get();
final User user = ctx.user();
final SecurityAudit audit = ((RoutingContextInternal) ctx).securityAudit();
audit.authorization(authorization);
audit.user(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public Future<User> authenticate(RoutingContext ctx) {
return Future.failedFuture(new HttpException(500, new IllegalStateException("No callback mounted!")));
}

final User user = ctx.user().get();
final User user = ctx.user();

if (user == null) {
return Future.failedFuture(new HttpException(401));
Expand Down Expand Up @@ -145,7 +145,7 @@ private void mountRegister() {
.method(HttpMethod.POST)
.order(order - 1)
.handler(ctx -> {
final User user = ctx.user().get();
final User user = ctx.user();
if (user == null || user.get("username") == null) {
ctx.fail(new VertxException("User object misses 'username' attribute", true));
return;
Expand All @@ -169,7 +169,7 @@ private void mountVerify() {
.method(HttpMethod.POST)
.order(order - 1)
.handler(ctx -> {
final User user = ctx.user().get();
final User user = ctx.user();
if (user == null || user.get("username") == null) {
ctx.fail(new VertxException("User object misses 'username' attribute", true));
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public JWTAuthHandler scopeDelimiter(String delimiter) {
*/
@Override
public void postAuthentication(RoutingContext ctx) {
final User user = ctx.user().get();
final User user = ctx.user();
if (user == null) {
// bad state
ctx.fail(403, new VertxException("no user in the context", true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ public void postAuthentication(RoutingContext ctx) {
final List<String> scopes = getScopesOrSearchMetadata(this.scopes, ctx);

if (scopes.size() > 0) {
final User user = ctx.user().get();
final User user = ctx.user();
if (user == null) {
// bad state
ctx.fail(403, new VertxException("no user in the context", true));
Expand Down Expand Up @@ -506,7 +506,7 @@ private void mountCallback() {
.andThen(op -> audit.audit(Marker.AUTHENTICATION, op.succeeded()))
.onFailure(ctx::fail)
.onSuccess(user -> {
((UserContextInternal) ctx.user())
((UserContextInternal) ctx.userContext())
.setUser(user);
String location = resource != null ? resource : "/";
if (session != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ private Future<Void> flush(RoutingContext context, boolean skipCrc, boolean igno
Boolean storeUser = context.get(SESSION_STOREUSER_KEY);
if (storeUser != null && storeUser) {
// during the request the user might have been removed
if (context.user().get() != null) {
if (context.user() != null) {
session.put(SESSION_USER_HOLDER_KEY, new UserHolder(context));
}
}
Expand Down Expand Up @@ -368,7 +368,7 @@ public Future<Void> setUser(RoutingContext context, User user) {
if (!cookieless) {
context.response().removeCookie(sessionCookieName, false);
}
((UserContextInternal) context.user())
((UserContextInternal) context.userContext())
.setUser(user);
// signal we must store the user to link it to the session
context.put(SESSION_STOREUSER_KEY, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public Future<User> authenticate(RoutingContext ctx) {
return Future.failedFuture(new HttpException(500, new IllegalStateException("No callback mounted!")));
}

final User user = ctx.user().get();
final User user = ctx.user();

if (user == null) {
return Future.failedFuture(new HttpException(401));
Expand Down Expand Up @@ -143,7 +143,7 @@ private void mountRegister() {
.method(HttpMethod.POST)
.order(order - 1)
.handler(ctx -> {
final User user = ctx.user().get();
final User user = ctx.user();
if (user == null || user.get("username") == null) {
ctx.fail(new VertxException("User object misses 'username' attribute", true));
return;
Expand All @@ -167,7 +167,7 @@ private void mountVerify() {
.method(HttpMethod.POST)
.order(order - 1)
.handler(ctx -> {
final User user = ctx.user().get();
final User user = ctx.user();

if (user == null || user.get("username") == null) {
ctx.fail(new VertxException("User object misses 'username' attribute", true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ public UserHolder(RoutingContext context) {
public synchronized void refresh(RoutingContext context) {
if (this.context != null) {
// this is a new object instance or already refreshed
user = this.context.user().get();
user = this.context.user();
}
// refresh the context
this.context = context;
if (user != null) {
((UserContextInternal) this.context.user())
((UserContextInternal) this.context.userContext())
.setUser(user);
}
}
Expand All @@ -63,7 +63,7 @@ public void writeToBuffer(Buffer buffer) {
final User user;

synchronized (this) {
user = context != null ? context.user().get() : this.user;
user = context != null ? context.user() : this.user;
// clear the context as this holder is not in a request anymore
context = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public Future<User> authenticate(RoutingContext ctx) {
return Future.failedFuture(new HttpException(500, new IllegalStateException("No callback mounted!")));
}

final User user = ctx.user().get();
final User user = ctx.user();

if (user == null) {
return Future.failedFuture(new HttpException(401));
Expand Down Expand Up @@ -301,7 +301,7 @@ private void mountResponse() {
.onSuccess(user -> {
audit.audit(Marker.AUTHENTICATION, true);
// save the user into the context
((UserContextInternal) ctx.user())
((UserContextInternal) ctx.userContext())
.setUser(user);
// the user has upgraded from unauthenticated to authenticated
// session should be upgraded as recommended by owasp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,6 @@ public Session webSession() {

@Override
public User webUser() {
return routingContext.user().get();
return routingContext.user();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.auth.User;
import io.vertx.ext.auth.audit.SecurityAudit;
import io.vertx.ext.web.*;

Expand Down Expand Up @@ -195,8 +194,8 @@ public HttpServerResponse response() {
}

@Override
public UserContext user() {
return decoratedContext.user();
public UserContext userContext() {
return decoratedContext.userContext();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ public boolean isSessionAccessed() {
}

@Override
public UserContext user() {
public UserContext userContext() {
if (identity == null) {
identity = new UserContextImpl(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ public boolean isSessionAccessed() {
}

@Override
public UserContext user() {
return inner.user();
public UserContext userContext() {
return inner.userContext();
}

@Override
Expand Down
Loading

0 comments on commit 0a830cf

Please sign in to comment.