eclipse-vertx / vertx-auth Goto Github PK
View Code? Open in Web Editor NEWLicense: Apache License 2.0
License: Apache License 2.0
Actually the signing algorithm is the same as the certificate, but in some cases you must use another.
CryptoSignature(final X509Certificate certificate, final PrivateKey privateKey) {
this.certificate = certificate;
this.privateKey = privateKey;
try {
this.sig = Signature.getInstance(certificate.getSigAlgName());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
In the "Google Cloud Plataform" we need to sign the JWT with SHA256withRSA using the private key of PKCS#12 certificate. The certificate is generated by Google and the sign algorithm of certificate is SHA1withRSA :(
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
Update parent version and a couple of dependencies.
I'm trying to integrate jwt token in my vertx but can't generate a token.
I got the exception below:
java.lang.RuntimeException: Algorithm not supported
at io.vertx.ext.auth.jwt.impl.JWT.sign(JWT.java:171)
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.generateToken(JWTAuthProviderImpl.java:145)
at ca.mavencode.pga.handler.AuthHandler.lambda$handle$5(AuthHandler.java:42)
at ca.mavencode.pga.handler.AuthHandler$$Lambda$19/1795160029.handle(Unknown Source)
at ca.mavencode.pga.jdbc.impl.JDBCAuthImpl.lambda$authenticate$1(JDBCAuthImpl.java:66)
at ca.mavencode.pga.jdbc.impl.JDBCAuthImpl$$Lambda$20/305717969.accept(Unknown Source)
at ca.mavencode.pga.jdbc.impl.JDBCAuthImpl.lambda$null$3(JDBCAuthImpl.java:119)
at ca.mavencode.pga.jdbc.impl.JDBCAuthImpl$$Lambda$24/394295754.handle(Unknown Source)
at io.vertx.core.impl.FutureImpl.checkCallHandler(FutureImpl.java:135)
at io.vertx.core.impl.FutureImpl.setHandler(FutureImpl.java:100)
at io.vertx.core.impl.ContextImpl.lambda$null$13(ContextImpl.java:288)
at io.vertx.core.impl.ContextImpl$$Lambda$26/456330793.handle(Unknown Source)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$15(ContextImpl.java:314)
at io.vertx.core.impl.ContextImpl$$Lambda$3/1729958231.run(Unknown Source)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:357)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
at java.lang.Thread.run(Thread.java:745)
But I can see these logs on my console,
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: HS256 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: HS384 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: HS512 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: RS256 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: RS384 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: RS512 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: ES256 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: ES384 not available
Sep 19, 2015 6:18:41 PM io.vertx.ext.auth.jwt.impl.JWT
INFO: ES512 not available
How can I resolve this and generate jwt tokens
Btw, I generated my keystore and added it to my classpath
keytool -genseckey -keystore keystore.jck -storetype jceks -storepass password -keyalg AES -keysize 256 -alias pga -keypass password
Currently we have user.hasRole(String)
and user.hasPermission(String)
even though the separation of roles
and permissions
sounds logic there are some deficiencies with the current implementation.
The first false assumption is that roles and permissions are independent and relate to a user. So say that user Paulo
has role dev
and permission push
. Now lets assume the whole application knows about the roles dev
and devops
and a dev
role can push
code and a devops
role can push
releases into production.
Now with our model if we want to assert if Paulo
can push
to production we need to do:
paulo.hasRole("devops") && paulo.hasPermission("push")
The logic here would fail since false
&& true
is false
. Now just say that because I am the lead developer i might have read
access to prod to pull logs or something... so now Paulo
is a dev
with push
permissions and devops
with read
permissions.
The same check from above will assert true
even tough it is not correct. The hasPermission
has no context about from which role
to check the permission for.
How can we fix this:
We need to refactor the User
to have a method hasAuthority(String)
if we like the Spring style or isPermitted(String)
if we like the Shiro style. After reading both I am tending for Shiro...
Now the assertion is a String, both Spring and Shiro have conventions about the format of the Strings. Looking at Shiro a authority has the format:
<role or domain>[:<action>[:<instance>]]
examples would be:
printers:print:color_printer_1st_floor
devops:read
dev:push
The impact is that using this approach we can have the same model fitting all current implementations:
The Strings are opaque so they only have specific meaning to the implementations and no assumptions on the format is made by vertx-auth
, the usage of the format above is just an example and if one prefers can use String notation:
Role_devops
Role_dev
devops:push
devops:read
dev:push
Since the assumption is that the String are opaque it is to the implementation of auth
providers to define if they support or not wildcards, e.g.: printers:print:*
.
The skip parameter is too eager. The code checks for whether or not the skip string contains the request string:
if (skip != null && skip.contains(request.path())) {
context.next();
return;
}
If the skip String is configured such as '/health' and the request.path()
== '/' then the skip execution always occurs which is probably not what was intended?
I'm not sure what the best behavior here is... My suggestion would be to make it so that if someone specifies a skip that does not end in * or /* then the check should be for equality, for example, only skip if request.path().equals(skip)
. If the skip String is, for example, instead /health* or /health/* then it should should work as request.path().startsWith(skip)
. Perhaps the inverse should be true if someone specifies a skip string preceded by * or */.
Not public at the moment. Trivial to see the problem though.
I worked around the issue by sub classing the JWTAuthHandlerImpl and writing my own skip implementation that works for my specific situation.
Hi,
I've been trying to migrate our code over to the new Authenticaton service. However, I could not find anything equivalent to Shiro Subject.isRemembered ?
http://shiro.apache.org/static/1.2.3/apidocs/org/apache/shiro/subject/Subject.html#isRemembered%28%29
IMHO, this feature is very important but seems to be currently missing from Vertx.
The Javascript example for vertx mongo auth just does not work.
https://groups.google.com/forum/#!topic/vertx/AfjHVJy4wtk has already raised the issue. I am repeating it here to see if it helps.
Just follow the documentation to create a JS vertx mongo auth client. Call to authenticate fails with a TypeErrpr. https://github.com/markus-simon/auth example is linked from the Google Groups link above
This is necessary for them to be deployed by vertx-maven-service-factory, see recent vertx-dev discussion
http://localhost:8080/callback?redirect_uri=/private/somepage/test leads to unauthorized acces while http://localhost:8080/private/somepage/test starts auth process correctly.
Output:
Welcome to the protected resource! :
{
"error" : "bad_verification_code",
"error_description" : "The code passed is incorrect or expired.",
"error_uri" : "https://developer.github.com/v3/oauth/#bad-verification-code"
}
https://gist.github.com/amoAHCP/b3509d859096952caf76f46665835525
This is the code in MongoAuthImpl
String permissionField = config.getString(PROPERTY_PERMISSION_FIELD);
if (roleField != null) {
setPermissionField(permissionField);
I think the if condition should be
if (permissionField != null) {
Hi @pmlopes @vietj I looked into the shiro eample in vertx-auth but could not find equivalent to SpringBoot's LDAP auth:
https://spring.io/guides/gs/authenticating-ldap/
More specifically, how to use a bind DN (manager DN) to authenticate users - using group search base and search filter? Here is what we are doing with Spring:
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userSearchFilter(
"((sAMAccountName={0})(objectclass=organizationalPerson))")
.userSearchBase("OU="+environment.getProperty("ldap.user-search-base.name"))
.groupSearchFilter("(member={0})")
.groupSearchBase("OU=Global-Groups")
.contextSource().url(environment.getProperty("ldap.url"))
.managerDn(environment.getProperty("ldap.conn.user"))
.managerPassword(environment.getProperty("ldap.conn.pwd"));
setAuthenticationManager(auth.getObject());
}
Is this something supported by vetx-auth right now? or a future feature? Without a similar LDAP auth as SprintBoot offering, it is hard to for us to use vertx-web to migrate existing spring web projects fully over to vertx.
Please advise. Thanks!
Alan
For some reason the order of inclusion of Vert.x JS components matters: putting the router before shiro auth causes this error on the 3.0.0 release upon successful authentication:
Unhandled exception
vertx-js/util/utils.js:208 TypeError: undefined is not an Object
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:213)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:185)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:172)
at jdk.nashorn.internal.objects.Global.checkObject(Global.java:1673)
at jdk.nashorn.internal.objects.NativeObject.create(NativeObject.java:261)
at jdk.nashorn.internal.scripts.Script$Recompilation$122$5673AA$\^eval\_#88\!17\^eval\_.L:1$convReturnVertxGen(vertx-js/util/utils.js:208)
at jdk.nashorn.internal.scripts.Script$Recompilation$154$2273A$\^eval\_#88\!17\^eval\_.L:1$AuthProvider$authenticate$L:60(vertx-auth-common-js/auth_provider.js:62)
at io.vertx.core.Handler$$NashornJavaAdapter.handle(Unknown Source)
at io.vertx.core.impl.FutureImpl.checkCallHandler(FutureImpl.java:135)
at io.vertx.core.impl.FutureImpl.setHandler(FutureImpl.java:100)
at io.vertx.core.impl.ContextImpl.lambda$null$13(ContextImpl.java:288)
at io.vertx.core.impl.ContextImpl$$Lambda$12/390709726.handle(Unknown Source)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$15(ContextImpl.java:314)
at io.vertx.core.impl.ContextImpl$$Lambda$7/1318310462.run(Unknown Source)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:357)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
at java.lang.Thread.run(Thread.java:745)
That was from vertx run shirotest.js
with the following code and a shirotest.properties file containing user.correct = pw
. It works fine if you reverse the order and include shiro_auth before router or if you use invalid credentials. Perhaps something to do with creating the User object?
var Router = require("vertx-web-js/router");
var ShiroAuth = require("vertx-auth-shiro-js/shiro_auth");
var shiroConfig = {
"properties_path" : "file:shirotest.properties"
};
var shiro = ShiroAuth.create(vertx, 'PROPERTIES', shiroConfig);
var authInfo = {
"username" : "correct",
"password" : "pw"
};
shiro.authenticate(authInfo, function (res, res_err) {
if (res_err === null) {
logger.info("yep");
} else {
logger.info("nope");
}
});
Hi,
Currently, as JWT
class is trying to load MAC algorithm of configured keystore file, it logs NullPointerException if an algorithm isn't supported, as shown in this line. This makes the application logs to be polluted with rather meaningless error stack trace like so
22:49:23.968 [vert.x-eventloop-thread-2] io.vertx.ext.auth.jwt.impl.JWT [WARN ] [API] - HS256 not supported
java.lang.NullPointerException: null
at io.vertx.ext.auth.jwt.impl.JWT.getMac(JWT.java:86) ~[vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.impl.JWT.<init>(JWT.java:53) ~[vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.<init>(JWTAuthProviderImpl.java:77) [vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.JWTAuth.create(JWTAuth.java:39) [vertx-auth-jwt-3.0.0-milestone6.jar:na]
at com.panjiesw.std.api.ApiVerticle.createAuthProvider(ApiVerticle.java:115) [main/:na]
at com.panjiesw.std.api.ApiVerticle.startModule(ApiVerticle.java:88) [main/:na]
at com.panjiesw.std.api.ApiVerticle.lambda$handleService$1(ApiVerticle.java:78) [main/:na]
at com.panjiesw.std.api.ApiVerticle$$Lambda$8/383266732.handle(Unknown Source) [main/:na]
at io.vertx.core.impl.DeploymentManager.lambda$reportResult$159(DeploymentManager.java:436) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.DeploymentManager$$Lambda$14/677334899.handle(Unknown Source) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$15(ContextImpl.java:312) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.ContextImpl$$Lambda$7/1448061896.run(Unknown Source) [vertx-core-3.0.0-milestone6.jar:na]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
22:49:23.969 [vert.x-eventloop-thread-2] io.vertx.ext.auth.jwt.impl.JWT [WARN ] [API] - HS384 not supported
java.lang.NullPointerException: null
at io.vertx.ext.auth.jwt.impl.JWT.getMac(JWT.java:86) ~[vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.impl.JWT.<init>(JWT.java:53) ~[vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.<init>(JWTAuthProviderImpl.java:77) [vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.JWTAuth.create(JWTAuth.java:39) [vertx-auth-jwt-3.0.0-milestone6.jar:na]
at com.panjiesw.std.api.ApiVerticle.createAuthProvider(ApiVerticle.java:115) [main/:na]
at com.panjiesw.std.api.ApiVerticle.startModule(ApiVerticle.java:88) [main/:na]
at com.panjiesw.std.api.ApiVerticle.lambda$handleService$1(ApiVerticle.java:78) [main/:na]
at com.panjiesw.std.api.ApiVerticle$$Lambda$8/383266732.handle(Unknown Source) [main/:na]
at io.vertx.core.impl.DeploymentManager.lambda$reportResult$159(DeploymentManager.java:436) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.DeploymentManager$$Lambda$14/677334899.handle(Unknown Source) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$15(ContextImpl.java:312) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.ContextImpl$$Lambda$7/1448061896.run(Unknown Source) [vertx-core-3.0.0-milestone6.jar:na]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
22:49:23.971 [vert.x-eventloop-thread-2] io.vertx.ext.auth.jwt.impl.JWT [WARN ] [API] - HS512 not supported
java.lang.NullPointerException: null
at io.vertx.ext.auth.jwt.impl.JWT.getMac(JWT.java:86) ~[vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.impl.JWT.<init>(JWT.java:53) ~[vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.<init>(JWTAuthProviderImpl.java:77) [vertx-auth-jwt-3.0.0-milestone6.jar:na]
at io.vertx.ext.auth.jwt.JWTAuth.create(JWTAuth.java:39) [vertx-auth-jwt-3.0.0-milestone6.jar:na]
at com.panjiesw.std.api.ApiVerticle.createAuthProvider(ApiVerticle.java:115) [main/:na]
at com.panjiesw.std.api.ApiVerticle.startModule(ApiVerticle.java:88) [main/:na]
at com.panjiesw.std.api.ApiVerticle.lambda$handleService$1(ApiVerticle.java:78) [main/:na]
at com.panjiesw.std.api.ApiVerticle$$Lambda$8/383266732.handle(Unknown Source) [main/:na]
at io.vertx.core.impl.DeploymentManager.lambda$reportResult$159(DeploymentManager.java:436) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.DeploymentManager$$Lambda$14/677334899.handle(Unknown Source) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$15(ContextImpl.java:312) [vertx-core-3.0.0-milestone6.jar:na]
at io.vertx.core.impl.ContextImpl$$Lambda$7/1448061896.run(Unknown Source) [vertx-core-3.0.0-milestone6.jar:na]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) [netty-all-4.0.25.Final.jar:4.0.25.Final]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
The log should not include the error stack trace i think, like in SIGNATURE loops below that line
As per my exploration of using vertx with shiro and stormpath here https://groups.google.com/forum/?fromgroups=#!topic/vertx/rO8xlDof1qA
I have encountered a defect.
If in my code I do this:
router.route().handler((RoutingContext context) -> {
context.user().isAuthorised("role:84c2a410-b761-44cd-88c7-a8bba0e976cb+admins", (AsyncResult<Boolean> res) -> {
if (res.succeeded()) {
boolean hasPermission = res.result();
if (hasPermission) {
context.next();
} else {
context.response().setStatusCode(403).end("You do not have access to that group!");
}
} else {
context.response().setStatusCode(403).end("Error asking if authorised");
}
});
});
The isAuthorised
calls through to stormpath's implementation of doGetAuthorizationInfo
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
assertState();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
String href = getAccountHref(principals);
...
protected String getAccountHref(PrincipalCollection principals) {
Collection c = principals.fromRealm(getName());
//Based on the createPrincipals implementation above, the first one is the Account href:
return (String) c.iterator().next();
}
Which calls vert'x:
public class SimplePrincipalCollection implements PrincipalCollection {
...
@Override
public Collection fromRealm(String realmName) {
return null;
}
And is hardcoded to null. And thus exceptions in getAccountHref
Scenario: A JavaScript UI that uses the KeyCloak redirect flow, and a Vert.x REST backend. The UI authenticates with the redirect and gets a token from KeyCloak. The token is added to each request to the Vert.x backend.
The KeyCloak token is, according the KeyCloak docs, "an extension of JWT". The token is self contained, meaning that user info such as the user's roles are embedded in the token. To check authorization for a specific action on the Vert.x backend, the backend would have to verify the token (using the public key), and read the roles from the token. No communication with KeyCloak is required.
Problem: The oauth2 module for Vert.x supports KeyCloak, but only the redirect flow. This is not useful in the scenario where Vert.x is only used for serving the backend. The jwt module sort of does the right thing, but doesn't seem to support KeyCloak token. This has to do with the specific format of the token, but I'm not sure about the details of this problem.
This should be supported out of the box. I did create a workaround, but this relies on an implementation class from the oauth2 module. Alternatively one of the available 3rd party JWT libraries could be used, but support in Vert.x would be a lot easier.
The following is an example of the code that I'm currently using for auth, based on the TokenVerifier
, which is an implementation class.
import io.vertx.ext.auth.oauth2.impl.crypto.TokenVerifier;
public void handle(RoutingContext req) {
String authHeader = req.request().getHeader("Authorization");
if(authHeader != null) {
String jwt = authHeader.substring(authHeader.indexOf(" ") + 1);
TokenVerifier tokenVerifier = new TokenVerifier(m_config.keycloakPublicKey);
JsonObject verify = tokenVerifier.verify(jwt);
req.setUser(new User(new WebUser(verify)));
req.next();
} else {
req.response().setStatusCode(403).end();
}
}
The WebUser
type is just a wrapper.
public class WebUser implements User{
private final JsonObject m_principal;
public WebUser(JsonObject principal) {
this.m_principal = principal;
}
@Override
public User isAuthorised(String authority, Handler<AsyncResult<Boolean>> resultHandler) {
return this;
}
@Override
public User clearCache() {
return this;
}
@Override
public JsonObject principal() {
return m_principal;
}
@Override
public void setAuthProvider(AuthProvider authProvider) {
}
}
Once we decide on the correct solution I would be happy to work on a PR.
OAuth getToken never flags result.failed()
as true
for invalid code sent. I am testing this with GitHub provider. Note in the debugger image that the result.failed()
is always false
and docs (http://vertx.io/docs/vertx-auth-oauth2/java/) says it should be true
on error.
oauth2.getToken(new JsonObject().put("code", code).put("redirect_uri", "http://localhost:8080/callback"), res -> {
if (res.failed()) {
// error, the code provided is not valid
} else {
// save the token and continue...
}
});
Right now the JWT module requires a private key for asymetric keys in order to be used, however, if you're only interested in decoding and verifying a key then this is an unnecessary additional piece of security data that needs to be stored in the key store. The piece of code responsible for this is located here:
X509Certificate certificate = getCertificate(keyStore, alg);
PrivateKey privateKey = getPrivateKey(keyStore, keyStorePassword, alg);
if (certificate != null && privateKey != null) {
tmp.put(alg, new CryptoSignature(alias.get(alg), certificate, privateKey));
} else {
log.info(alg + " not available");
}
Can the requirement that a private key be present be lifted?
I noticed the MongoAuth is assuming that users are identified using a username. This applies to both the API (eg from MongoAuthImpl
: public void insertUser(String username, String password,...)
), as well as any error messages: (eg: resultHandler.handle((Future.failedFuture("Username must be set for authentication.")));
).
I would like to use user emails rather than usernames, and although I perfectly can using the customisation options, I do feel there is a bit of a mismatch.
I suggest replacing username by userIdentifier or something similar. This could be changed without breaking compatibility.
Currently the final redirect is handled internally, however this can cause problems if a user refreshes the html page since a new token request is done and invalidates the token.
Doing a HTTP redirect (would enforce users use a session handler) so state is preserved and no issues would happen due to refresh page.
at the moment in Vert.x Shell we create auth from options, it would be good to have them in this project for 3.2 instead, see : https://github.com/vert-x3/vertx-shell/tree/master/src/main/java/io/vertx/ext/shell/auth
I created a Keycloak handler as shown in this video.
Vertx vertx = Vertx.vertx();
Router router = Router.router(vertx);
OAuth2AuthHandler oauth2 = OAuth2AuthHandler.create(OAuth2Auth.createKeycloak(vertx, OAuth2FlowType.AUTH_CODE, new JsonObject("...")), "http://localhost:8282");
oauth2.setupCallback(router.get("/callback"));
router.route("/secure/*").handler(oauth2);
router.route("/secure/test").handler(rc -> {
rc.response().end("This is a secure page!");
});
vertx.createHttpServer().requestHandler(router::accept).listen(8282);
The request to secure/test
gets redirected to the Keycloak login page as expected. After login I get redirected like url http://localhost:8282/callback?redirect_uri=/secure/test&state=&code=mYYbNf79vby_ALu5M2swWwJ0Com4eto5RQNJpPjjduQ.b09a7d59-ef84-4dd1-a981-b16a396fed16
, which shows This is a secure page!
correctly.
When I refresh the page however, it fails. The page returns "Internal Server Error", and on the application's console I see:
io.vertx.ext.web.impl.RoutingContextImplBase
SEVERE: Unexpected exception in route
io.vertx.core.impl.NoStackTraceThrowable: Bad Request
When clustered using Hazelcast, create JWT Token, validate it by calling provider.authenticate() then routingContext.setUser() so it is available immediately. Next requests that come in all fail with:
19:19:56.440 [vert.x-eventloop-thread-2] ERROR i.v.e.w.impl.RoutingContextImplBase - Unexpected exception in route
com.hazelcast.nio.serialization.HazelcastSerializationException: Problem while reading DataSerializable, namespace: 0, id: 0, class: 'io.vertx.spi.cluster.hazelcast.impl.HazelcastAsyncMap$DataSerializableHolder', exception: Failed to load class io.vertx.core.VertxException: java.lang.InstantiationException: io.vertx.ext.auth.jwt.impl.JWTUser
at com.hazelcast.nio.serialization.DataSerializer.read(DataSerializer.java:120) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.nio.serialization.DataSerializer.read(DataSerializer.java:39) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.nio.serialization.StreamSerializerAdapter.read(StreamSerializerAdapter.java:41) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.nio.serialization.SerializationServiceImpl.toObject(SerializationServiceImpl.java:276) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.spi.impl.NodeEngineImpl.toObject(NodeEngineImpl.java:200) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.map.impl.MapServiceContextImpl.toObject(MapServiceContextImpl.java:281) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.map.impl.proxy.MapProxySupport.toObject(MapProxySupport.java:1114) ~[hazelcast-3.5.jar:3.5]
at com.hazelcast.map.impl.proxy.MapProxyImpl.get(MapProxyImpl.java:82) ~[hazelcast-3.5.jar:3.5]
at io.vertx.spi.cluster.hazelcast.impl.HazelcastAsyncMap.lambda$get$13(HazelcastAsyncMap.java:46) ~[vertx-hazelcast-3.0.0.jar:na]
at io.vertx.spi.cluster.hazelcast.impl.HazelcastAsyncMap$$Lambda$72/589483425.handle(Unknown Source) ~[na:na]
at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$14(ContextImpl.java:279) ~[vertx-core-3.0.0.jar:na]
at io.vertx.core.impl.ContextImpl$$Lambda$35/1335061928.run(Unknown Source) ~[na:na]
at io.vertx.core.impl.OrderedExecutorFactory$OrderedExecutor.lambda$new$161(OrderedExecutorFactory.java:91) ~[vertx-core-3.0.0.jar:na]
at io.vertx.core.impl.OrderedExecutorFactory$OrderedExecutor$$Lambda$34/711310213.run(Unknown Source) ~[na:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_25]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: java.lang.IllegalStateException: Failed to load class io.vertx.core.VertxException: java.lang.InstantiationException: io.vertx.ext.auth.jwt.impl.JWTUser
at io.vertx.spi.cluster.hazelcast.impl.HazelcastAsyncMap$DataSerializableHolder.readData(HazelcastAsyncMap.java:178) ~[vertx-hazelcast-3.0.0.jar:na]
at com.hazelcast.nio.serialization.DataSerializer.read(DataSerializer.java:111) ~[hazelcast-3.5.jar:3.5]
... 16 common frames omitted
Caused by: io.vertx.core.VertxException: io.vertx.core.VertxException: java.lang.InstantiationException: io.vertx.ext.auth.jwt.impl.JWTUser
at io.vertx.ext.web.sstore.impl.SessionImpl.readDataFromBuffer(SessionImpl.java:309) ~[vertx-web-3.0.0.jar:na]
at io.vertx.ext.web.sstore.impl.SessionImpl.readFromBuffer(SessionImpl.java:145) ~[vertx-web-3.0.0.jar:na]
at io.vertx.spi.cluster.hazelcast.impl.HazelcastAsyncMap$DataSerializableHolder.readData(HazelcastAsyncMap.java:176) ~[vertx-hazelcast-3.0.0.jar:na]
... 17 common frames omitted
Caused by: io.vertx.core.VertxException: java.lang.InstantiationException: io.vertx.ext.auth.jwt.impl.JWTUser
at io.vertx.ext.web.handler.impl.UserHolder.readFromBuffer(UserHolder.java:79) ~[vertx-web-3.0.0.jar:na]
at io.vertx.ext.web.sstore.impl.SessionImpl.readDataFromBuffer(SessionImpl.java:299) ~[vertx-web-3.0.0.jar:na]
... 19 common frames omitted
Caused by: java.lang.InstantiationException: io.vertx.ext.auth.jwt.impl.JWTUser
at java.lang.Class.newInstance(Class.java:423) ~[na:1.8.0_25]
at io.vertx.ext.web.handler.impl.UserHolder.readFromBuffer(UserHolder.java:75) ~[vertx-web-3.0.0.jar:na]
... 20 common frames omitted
Caused by: java.lang.NoSuchMethodException: io.vertx.ext.auth.jwt.impl.JWTUser.<init>()
at java.lang.Class.getConstructor0(Class.java:3074) ~[na:1.8.0_25]
at java.lang.Class.newInstance(Class.java:408) ~[na:1.8.0_25]
... 21 common frames omitted
That last "caused by" seems to say that something wants it to have a default constructor and it does not?
This is the next issue related to #21, see that ticket for the setup.
protected String getAccountHref(PrincipalCollection principals) {
Collection c = principals.fromRealm(getName());
//Based on the createPrincipals implementation above, the first one is the Account href:
return (String) c.iterator().next();
}
The getName()
returns com.stormpath.shiro.realm.ApplicationRealm_0
and then in principals.fromRealm
it does:
public Collection fromRealm(String realmName) {
if (realmPrincipals == null || realmPrincipals.isEmpty()) {
return Collections.EMPTY_SET;
}
Set principals = realmPrincipals.get(realmName);
if (principals == null || principals.isEmpty()) {
principals = Collections.EMPTY_SET;
}
return Collections.unmodifiableSet(principals);
}
Where the realmPrincipals
is a map with one entry: vertx-auth-shiro
So it seems stormpath is looking up by principal using it's name, but somehow only vertx-auth-shiro
has been registered.
New key for playing around if you didn't sign up yourself:
apiKey.id = 1Z1YUWJA1YVHAICAOIU8P96VW
apiKey.secret = Bb9pCd07rzCOlQ7uLr1ZZF2Q/zKQi8dfGHerMJ8fBE8
java.lang.RuntimeException: Algorithm not supported
at io.vertx.ext.auth.jwt.impl.JWT.sign(JWT.java:180)
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.generateToken(JWTAuthProviderImpl.java:145)
at io.vertx.groovy.ext.auth.jwt.JWTAuth.generateToken(JWTAuth.groovy:55)
at io.vertx.groovy.ext.auth.jwt.JWTAuth$generateToken$0.call(Unknown Source)
public String sign(JsonObject payload, JsonObject options) {
final String algorithm = options.getString("algorithm", "HS256"); <<-- Supposed to be RS256?
Generate a token as such:
val payload = JsonObject()
.put("sub", "UserUnderTest")
.put("aud", "OrganizationUnderTest")
.put("iat", 1431695313)
.put("exp", 1747055313)
.put("roles", JsonArray(listOf("admin", "developer", "user")))
.put("permissions", JsonArray(listOf("read", "write", "execute")))
return authProvider.generateToken(payload, JWTOptions().setSubject("UserUnderTest").setAlgorithm("none"))
The output token is:
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0=.eyJzdWIiOiJVc2VyVW5kZXJUZXN0IiwiYXVkIjpbIk9yZ2FuaXphdGlvblVuZGVyVGVzdCJdLCJleHAiOjE3NDcwNTUzMTMsImlhdCI6MTQzMTY5NTMxMywicGVybWlzc2lvbnMiOlsicmVhZCIsIndyaXRlIiwiZXhlY3V0ZSJdLCJyb2xlcyI6WyJhZG1pbiIsImRldmVsb3BlciIsInVzZXIiXX0=.
This fails during JWT decode because of this code (there are only two generated segments)
String[] segments = token.split("\\.");
if (segments.length != 3) {
throw new RuntimeException("Not enough or too many segments");
}
mongoAuth.insertUser creates multiple users with the same name causing authentication to fail.
i would expect that insertuser will validate that the same user does not exists.
Google allows applications to communicate securely using just JWTs over its OAuth2 interface. This is also known as server to server communication and avoids the OAuth2 redirect flow.
We could already do this with the current JWT module but we could add an helper to simplify its usage.
This mode of communication is very useful for consuming APIs from google for example consuming good drive files.
It would be great to add examples to use different auth module in the project. Or please share examples in documentation if possible.
Thanks.
This is mostly a query to see if I have misunderstood the behaviour, but it seems that refreshLoginSession must be called immediately after a login, otherwise the session is timeout'd the first time the reaper is run.
Is it also intended that refreshLoginSession should be called manually to keep the login session alive? I would have guessed that calls to hasPermission() and hasRole() would keep the login session alive as well.
https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
Looks like JWT.java purely relies on what is in the token to specify the alogirithm. This could allow the attacker to attack a vertx server using asym algorithms by signing a token with the known public key, but setting the algorithm to HS256. Vertx would then verify the token purely using the public key instead of the private one.
public JWTAuthProviderImpl(Vertx vertx, JsonObject config) {
config should be expanded to support a "algorithm" parameter, and this should be passed down into JWT when it verifies the token.
Do not use asymmetric algorithms for your tokens. Use symmetric algos with a private signing key.
Decoding token with JWT created with no Keystore fails. This is because unsecured is set to true and cryptoMap is empty.
I'm not sure if it is a bug or a concision design decisions.
Not validating a signature in production is another problem in itself, I do realize that, however, I'm using JWT class directly as I have a very specific needs for AuthProvider and AuthHandler.
I stumbled across this issue unit testing my AuthProvider.
The interesting line is https://github.com/vert-x3/vertx-auth/blob/master/vertx-auth-jwt/src/main/java/io/vertx/ext/auth/jwt/impl/JWT.java#L187
Perhaps it should read:
if (!unsecure && crypto == null) { throw new RuntimeException("Algorithm not supported"); }
Also, the entire signature validation block would have to be skipped.
Any thoughts ?
token eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJwYXVsbyIsImlhdCI6MTQ0Mjk5ODIxNX0=.MEQCICUVOYsAvKSng-4SDaZBdcYTKLHtxZqHcl4wqvZcdseoAiBj7kGiOhyYES1wdpg0FashauDgue86oWmyQVYc7t7NEQ==
java.lang.RuntimeException: java.security.SignatureException: object not initialized for verification
at io.vertx.ext.auth.jwt.impl.CryptoSignature.verify(Crypto.java:85)
at io.vertx.ext.auth.jwt.impl.JWT.decode(JWT.java:158)
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.authenticate(JWTAuthProviderImpl.java:78)
at id.netzme.skyfeed.ConfigurationTest.testJWT(ConfigurationTest.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate
The following exception is thrown when logging in to the example app at https://github.com/vert-x3/vertx-examples/blob/master/web-examples/src/main/java/io/vertx/example/web/auth/Server.java
Currently the exception is swallowed as the DefaultSubjectContext that should log the error receives a NOPLogger, not sure why, may be due to Shiro using slf4j and the app being configured for JUL. Certainly in my project in which I have logback configured I see these exceptions, and in the demo app if you breakpoint inside DefaultSubjectContext.resolveSecurityManager you can see the exception get thrown.
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
at org.apache.shiro.subject.support.DefaultSubjectContext.resolveSecurityManager(DefaultSubjectContext.java:106)
at org.apache.shiro.mgt.DefaultSecurityManager.ensureSecurityManager(DefaultSecurityManager.java:411)
at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:333)
at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:183)
at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:283)
at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:256)
at io.vertx.ext.auth.shiro.impl.ShiroAuthProviderImpl.lambda$authenticate$3(ShiroAuthProviderImpl.java:79)
at io.vertx.ext.auth.shiro.impl.ShiroAuthProviderImpl$$Lambda$31/2109966893.handle(Unknown Source)
at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$14(ContextImpl.java:279)
at io.vertx.core.impl.ContextImpl$$Lambda$32/1669819723.run(Unknown Source)
at io.vertx.core.impl.OrderedExecutorFactory$OrderedExecutor.lambda$new$161(OrderedExecutorFactory.java:91)
at io.vertx.core.impl.OrderedExecutorFactory$OrderedExecutor$$Lambda$3/1309238149.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
i copy description from [forum thread re this issue ] :(https://groups.google.com/forum/#!topic/vertx/Jqk6R2buSDY)
we have a verticle that creates vertx-web routes and then starts an http server. on some routes we add a JWTAuthHandler to provide jwt based security.
the keystore,jceks file used for that matter is in the classpath.
all worked fine while we had 2 verticle instances, but once we increased the number of instances our verticle started to randomly (but frequently :) ) crash during deployment:
the two exceptions we've seen as the reason for crash are:
java.lang.RuntimeException:
java.io.FileNotFoundException: .vertx\file-cache-812c2a19-b5b6-4339-8a80-fabdfa90cb4e\jwt-keystore.jceks (The process cannot access the file because it is being used by another process)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.(JWTAuthProviderImpl.java:61)
at io.vertx.ext.auth.jwt.JWTAuth.create(JWTAuth.java:41)
at com.zzz.rest.verticles.RestServerVerticle.addJwtSecurity(RestServerVerticle.java:144)
at com.zzz.rest.verticles.RestServerVerticle.start(RestServerVerticle.java:78)
at io.vertx.core.impl.DeploymentManager.lambda$doDeploy$8(DeploymentManager.java:434)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$3(ContextImpl.java:359)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:339)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:393)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:742)
at java.lang.Thread.run(Thread.java:745)
and
java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:392)
at com.sun.crypto.provider.JceKeyStore.engineLoad(JceKeyStore.java:698)
at java.security.KeyStore.load(KeyStore.java:1445)
at io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.(JWTAuthProviderImpl.java:62)
at io.vertx.ext.auth.jwt.JWTAuth.create(JWTAuth.java:41)
at com.zzz.rest.verticles.RestServerVerticle.addJwtSecurity(RestServerVerticle.java:144)
at com.zzz.rest.verticles.RestServerVerticle.start(RestServerVerticle.java:78)
at io.vertx.core.impl.DeploymentManager.lambda$doDeploy$8( .java:434)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$3(ContextImpl.java:359)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:339)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:393)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:742)
at java.lang.Thread.run(Thread.java:745)
as you can see, in both cases the problem occurs while JWTAuth tries to load a keystore file from vertx cache. the exception is thrown from the following code in JWTAuthProviderImpl:
try (InputStream in = new FileInputStream(vertxInternal.resolveFile(keyStore.getString("path"))))
it seems the reading from the fileinputstream should be synchronized to prevent this from happen.
Please node service descriptor json file name needs to match maven coords for vertx-maven-service-factory dynamic deployment to work correctly, see recent vertx-dev discussion
sometimes JWT.decode will throw the RuntimeException("Signature verification failed") when we use blockingHandler or generateToken/authenticate in different thread.
I think it's because CryptoMac use mac.doFinal to generate digests and it's not thread-safe.
OAuth getToken can't set exceptionHandler to HttpClientRequest and don't call callback method when exception is thrown in HttpClientRequest.
When java.net.UnknownHostException was thrown (Google's OAuth API Server downed), my app couldn't response anything to browser.
I was trying to get an access token from facebook and noticed it returns text/plain which OAuth2API cannot handle. The error thrown is:
Access Token Error: Cannot handle content type: text/plain
Try to use the configuration described here to get an access token from facebook:
http://vertx.io/docs/vertx-auth-oauth2/java/
Here's someone else that ran into this:
http://stackoverflow.com/questions/35245955/vert-x-oauth2-facebook-api-call-to-get-access-token-fails-because-of-text-plain
client = provider.getVertx().createHttpClient(new HttpClientOptions() .setSsl(isSecure) .setDefaultHost(host) .setDefaultPort(port));
new client is created for the request. It would be nice to be able to control the client configuration from the overall OAuth2ClientOptions.
For example:
client = provider.getVertx().createHttpClient(config);
Wasn't that the intention #56 and #57 ?
At the moment I can't ignore SSL errors in my test environment or add keystore for the client.
Greg
all versions
In io.vertx.ext.auth.jwt.impl.JWT#decode you get the algorithm to use form the JWT header segment. But this let an attacker select the algorithm that is used to check the token. Just change the JWT header “alg” to “none” and you have a valid token!
add to io.vertx.ext.auth.test.jwt.JWTAuthProviderTest
@Test
public void testAcceptInvalidJWT() {
String[] segments = JWT_INVALID.split("\\.");
// All segment should be base64
String headerSeg = segments[0];
// change alg to none
JsonObject headerJson = new JsonObject(new String(Base64.getUrlDecoder().decode(headerSeg.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
headerJson.put("alg", "none");
headerSeg = Base64.getUrlEncoder().encodeToString(headerJson.encode().getBytes(StandardCharsets.UTF_8));
// fix time exp
String payloadSeg = segments[1];
JsonObject bodyJson = new JsonObject(new String(Base64.getUrlDecoder().decode(payloadSeg.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
bodyJson.put("exp", System.currentTimeMillis() + 10000);
payloadSeg = Base64.getUrlEncoder().encodeToString(headerJson.encode().getBytes(StandardCharsets.UTF_8));
String signatureSeg = segments[2];
// build attack token
String attackerJWT = headerSeg+"."+payloadSeg+"."+signatureSeg;
JsonObject authInfo = new JsonObject().put("jwt", attackerJWT);
authProvider.authenticate(authInfo, onFailure(thr -> {
assertNotNull(thr);
testComplete();
}));
await();
}
I am using shiro for authentication, I have noticed that in ShiroAuthProviderImpl.java the properties "username" and "password" are used to create an UsernamePasswordToken object but not the remember me flag (that is supported by UsernamePasswordToken):
@Override
public void authenticate(JsonObject authInfo, Handler<AsyncResult<User>> resultHandler) {
vertx.executeBlocking(fut -> {
SubjectContext subjectContext = new DefaultSubjectContext();
Subject subject = securityManager.createSubject(subjectContext);
String username = authInfo.getString("username");
String password = authInfo.getString("password");
AuthenticationToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
} catch (AuthenticationException e) {
throw new VertxException(e);
}
fut.complete(new ShiroUser(vertx, securityManager, subject, rolePrefix));
}, resultHandler);
}
Do you think that modifying the code above in something like the following will magically enable the remember me feature ?
@Override
public void authenticate(JsonObject authInfo, Handler<AsyncResult<User>> resultHandler) {
vertx.executeBlocking(fut -> {
SubjectContext subjectContext = new DefaultSubjectContext();
Subject subject = securityManager.createSubject(subjectContext);
String username = authInfo.getString("username");
String password = authInfo.getString("password");
Boolean rememberMe = Boolean.parseBoolean(authInfo.getString("rememberme")); <-- HERE
AuthenticationToken token = new UsernamePasswordToken(username, password, rememberMe); <-- HERE
try {
subject.login(token);
} catch (AuthenticationException e) {
throw new VertxException(e);
}
fut.complete(new ShiroUser(vertx, securityManager, subject, rolePrefix));
}, resultHandler);
}
I am fairly new to Shiro and Vert.x, so I am not sure if this will be enough and maybe you already have experience with this issue.
thanks ;)
I written some code to perform Basic Authentication with Vertx ShiroAuth.
JsonObject authConfigObject = new JsonObject();
authConfigObject.put(
PropertiesProviderConstants.PROPERTIES_PROPS_PATH_FIELD,
new File(appConfig.getUserPropertiesPath()).toURI().toString() /*to let shiro auto reload properties file */
);
ShiroAuthOptions shiroAuthOptions = new ShiroAuthOptions();
shiroAuthOptions.setType(ShiroAuthRealmType.PROPERTIES);
shiroAuthOptions.setConfig(authConfigObject);
Example properties file:
user.admin=12345678
user.staff=123
When user login with browser, vertx throw a null Throwable (stacktrace), hence we must add this stupid if block to handle it:
public void handleFailure(RoutingContext context) {
if (context.failure() == null || context.failure() instanceof FileNotFoundException) {
context.next();
return;
}
//handle another failure....
I feel that add that if block is a trick :(
At the last of the documents (http://vert-x3.github.io/docs/vertx-auth-shiro/groovy/), I see I can use other Realm
class MyRealm extends AuthorizingRealm {
// other codes.
}
import io.vertx.groovy.ext.auth.shiro.ShiroAuth;
def realm = new MyRealm();
def provider = ShiroAuth.create(vertx, realm);
But When I create an Realm, I see there is no method ShiroAuth.create(vertx, realm);
groovy.lang.MissingMethodException: No signature of method: static io.vertx.groovy.ext.auth.shiro.ShiroAuth.create() is applicable for argument types: (io.vertx.groovy.core.Vertx, MyRealm)
For 3.2 we would like to have some simple oauth2 support, the MVP is to support authentication using a third party such as Github/Facebook/Google
In general this is considered a fault of the spec.
An opinionated stance should be taken on this issue. Its frankly dumb this option made it into the spec.
I written some code to perform Basic Authentication with Vertx ShiroAuth.
JsonObject authConfigObject = new JsonObject();
authConfigObject.put(
PropertiesProviderConstants.PROPERTIES_PROPS_PATH_FIELD,
new File(appConfig.getUserPropertiesPath()).toURI().toString() /*to let shiro auto reload properties file */
);
ShiroAuthOptions shiroAuthOptions = new ShiroAuthOptions();
shiroAuthOptions.setType(ShiroAuthRealmType.PROPERTIES);
shiroAuthOptions.setConfig(authConfigObject);
Example properties file:
user.admin=12345678
user.staff=123
If I add new key-value to properties file, Shiro can detect and reload perfectly. But when I delete, shiro reload (the debug log said that) but nothing change (user can still login by using those deleted key-value).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.