I previously had some code working on Glassfish, but I want to port it to WildFly.
However, I cannot seem get the module to be invoked by WildFly. The ServletContextListener initializes the module as follows
AuthConfigFactory.getFactory()
.registerConfigProvider(new OpenIdConnectModuleConfigProvider(options, null),
"HttpServlet", getAppContext(sce), null);
"HttpServlet" is not Glassfish specific and appears to be referenced in https://github.com/wildfly/wildfly/blob/master/undertow/src/main/java/org/wildfly/extension/undertow/security/jaspi/JASPIAuthenticationMechanism.java?source=cc
Glassfish does not require a <logon-config> block on the web.xml and putting any variant in WildFly does not work (as expected)
The other place I am suspecting is how I calculate the application context identifier. For Glassfish I had
private String getAppContext(final ServletContextEvent sce) {
return sce.getServletContext()
.getVirtualServerName() + " "
+ sce.getServletContext()
.getContextPath();
}
Could it be different in WildFly? Though I saw the similar code in https://github.com/rdebusscher/secSpikeWeb/blob/master/src/main/java/org/omnifaces/security/jaspic/core/Jaspic.java#L300 as well
I have also tried adding to standalone.xml this block
<security-domain name="jaspi" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="org.wildfly.extension.undertow.security.jaspi.modules.HTTPSchemeServerAuthModule" flag="required"/>
</authentication-jaspi>
</security-domain>
And set <default-security-domain value="jaspi"/>
However it had no effect and putting a breakpoint in the module didn't show that it gets hit either.
In addition, there I couldn't find a to be a way of doing the following, in WildFly like I would in glassfish-web.xml but that can be another question
<security-role-mapping>
<role-name>users</role-name>
<group-name>https://helloworld</group-name>
</security-role-mapping>
The code is pretty big, but the gist of it can be found in
https://github.com/trajano/openid-connect/tree/openid-connect-1.0.1/openid-connect-jaspic-module
and
https://github.com/trajano/openid-connect/tree/openid-connect-1.0.1/openid-connect-jaspic-sample
Note I am looking for it on the application level and not set a global server JASPI.
"HttpServlet" is not Glassfish specific
That's correct, AFAIK this is a standard identifier to say for which subsystem in Java EE the auth module is going to be registered. But there's only one other valid value and that's something with "soap" in it (not sure).
Could it be different in WildFly?
No, it's a standard way.
And set <default-security-domain value="jaspi"/>
The recommended way should be this in standalone.xml:
<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>
And then putting the following in WEB-INF/jboss-web.xml:
<jboss-web>
<security-domain>jaspitest</security-domain>
</jboss-web>
This should be enough. It's what I use on WildFly 8.2 and 9.0, and it's what the Java EE samples project uses. But setting the default domain should also really work as you did, and you activation code is close enough too, so I'm not sure if the above will make a difference in your case.
Alternatively there's a JBoss specific programmatic way to activate JASPIC:
String securityDomain = "other";
IdentityManager identityManager = deploymentInfo.getIdentityManager();
if (identityManager instanceof JAASIdentityManagerImpl) {
try {
Field securityDomainContextField =
JAASIdentityManagerImpl.class.getDeclaredField("securityDomainContext");
securityDomainContextField.setAccessible(true);
SecurityDomainContext securityDomainContext =
(SecurityDomainContext)
securityDomainContextField.get(identityManager);
securityDomain =
securityDomainContext.getAuthenticationManager().getSecurityDomain();
} catch (NoSuchFieldException | SecurityException |
IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
ApplicationPolicy applicationPolicy = new
ApplicationPolicy(securityDomain);
JASPIAuthenticationInfo authenticationInfo = new
JASPIAuthenticationInfo(securityDomain);
applicationPolicy.setAuthenticationInfo(authenticationInfo);
SecurityConfiguration.addApplicationPolicy(applicationPolicy);
deploymentInfo.setJaspiAuthenticationMechanism(new
JASPIAuthenticationMechanism(securityDomain, null));
deploymentInfo.setSecurityContextFactory(new
JASPICSecurityContextFactory(securityDomain));
You need to execute that from a io.undertow.servlet.ServletExtension
It's a shame that JBoss requires JASPIC to be activated. But one of the above shown methods should really work. I just verified them on a stock WildFly 9.0 and it worked there. The validateRequest method of a testing SAM is called correctly.
Related
Believe me, I know this question has been asked many times and has gotten an answer many times, and these answers seemed to have worked for some users. I've spent many hours trying the various proposed solutions and, while they work on Linux (Ubuntu) they seem to have no effect on Windows (Windows 10 Home with jdk1.8.0_161). The web application is using EclipseLink 2.5.0 for persistence.
I've tried including the mysql-connector-java-5.1.46-bin.jar file in the WAR archive (WEB-INF/lib; using the Deployment Assembly screen in Eclipse), copying it to the payara5/glassfish/lib folder, as well as the payara5/glassfish/domains/domain1/lib/ and payara5/glassfish/domains/domain1/lib/applibs folders. I also tried specifying the library when deploying the web application, i.e., putting mysql-connector-java-5.1.46-bin.jar as the value in the library field. I updated the CLASSPATH environment variable with the path to the JAR file. Every time, the server was restarted. None of these actions have any effect. Note that they did work on Linux Ubuntu.
See below for the well-known exception trace:
Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/rom
Error Code: 0
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:326)
at org.eclipse.persistence.sessions.DefaultConnector.connect(DefaultConnector.java:138)
at org.eclipse.persistence.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:170)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.setOrDetectDatasource(DatabaseSessionImpl.java:228)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:804)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:254)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:757)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:216)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:324)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:348)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:311)
...
Any thoughts would be greatly appreciated.
UPDATE: as a sanity check (got the idea thanks to #Abhi) I added the line
try {
System.out.println("JDBC driver: " +
Class.forName("com.mysql.jdbc.Driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Which correctly prints the following line (without throwing an exception):
JDBC driver: class com.mysql.jdbc.Driver
But does nothing to solve the problem. In other words, the driver seems to be loadable but somehow EclipseLink is not able to find it (?)
Looks like I'm able to answer my own question. I asked the exact same question on the Payara Forum and was recommended to define a data source instead of using the driver directly (#Chris pointed in this direction as well). A data source is likely the best way to go anyway but I wanted to avoid the complexity and use the simplest setup .. which clearly didn't work.
For reference, you can find the working setup below:
In Payara 5, goto JDBC > JDBC Connection Pools > New: enter a pool name, select javax.sql.DataSource as resource type, and MySql as vendor. On step 2, com.mysql.jdbc.jdbc2.optional.MysqlDataSource should be preselected for Datasource Classname. Fill out the Username and Password (e.g., root, changeit) properties under the Additional Properties header. Select finish. On the page for the newly created connection pool, select PING to make sure it was setup correctly.
In your persistence.xml file, make sure the persistence-unit element starts as follows:
<persistence-unit name="ROM" transaction-type="JTA">
<jta-data-source>java:global/<connection pool name></jta-data-source>
Create a web.xml file (this may also be done using Java Annotations):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<data-source>
<name>java:global/<connection pool name></name>
<class-name>com.mysql.jdbc.jdbc2.optional.MysqlDataSource</class-name>
<server-name>[host name, e.g., localhost]</server-name>
<port-number>3306</port-number>
<database-name>[db name]</database-name>
<user>[username, e.g., root]</user>
<password>[password]</password>
</data-source>
</web-app>
This configuration worked for me at least. Hoping this will help someone else down the road. Note that there are various useful settings for a connection pool - see e.g., here for more options.
to the line of code to connect:
con = DriverManager.getConnection(urlBaseDatos, usuario, clave);
Add the following:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
con = DriverManager.getConnection(urlBaseDatos, usuario, clave);
Naturally I concur with the answer here, which is "in an Application server you should use a DataSource".
Now just my two cents and to answer the original question:
From JDBC 4, you aren't required to register the driver anymore, and this line shouldn't be necessary:
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
See: https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html
So when using a JDK8+/EE8/JDBC4.2 compliant application server, you shouldn't be mandated to register the driver. Or so I thought...
Though, like you #William, I noticed Glassfish/Payara requires it. It's very strange. Maybe it has to do with the way it handles classloading?
Wildfly, in turn, does the right thing and automatically loads the driver without actually having to manually register it.
I have a problem after adding a message queue to Wildfly 10.1 (I'm using NetBeans 8.2). The message queue appears under the Resources/JMS Resources/JMS Destinations node in Wildfly Application Server, but when I create a message-driven bean using the NetBeans wizard, the Server Destinations drop-down is blank. (see screenshot).
It should show the jms queue I created. I've tried restarting Wildfly and NetBeans, but to no avail. Can anyone advise a solution?
That certainly looks like a bug (or at least a relic from the Glassfish support code), you may want to file a bug report for that. But in the mean time, it's not hard to work around. Assuming you created (via the Wildfly console) a queue named testq with jndi name java:/jms/testq you can just enter jms/testq as a "Project Destination" in the wizard and it will work. This will lead to the following (minimal) code
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/testq")
,#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class SomeMessageBean implements MessageListener {
and the onMessage handler:
#Override
public void onMessage(Message message) {
}
You could as well create a regular class and add the #MessageDriven annotation, there's really nothing magical about mdb's
I have a problem similar to the one described here.
I am using RESTEasy within a standalone Jetty application. When I start the application locally and call a service (e.g. localhost:16880/rest/user/login) bean validation works fine, i.e. I get validation errors like this:
[PARAMETER]
[UserService#login(arg0).appKey]
[app_key may not be null or empty]
[]
However, when I deploy my application to a remote host and call the same service (e.g. remotehost:16880/rest/user/login) bean validation is not invoked at all.
I am using the #ValidateRequest annotation for the service and #Valid annotation for the bean parameter.
My Resteasy version is 3.0.13.Final, though I have tried earlier versions as well. I have tried to write my custom validator, but that didn't work either.
I am puzzled why the validation works locally, but not on remote server. Any suggestions would be highly appreciated.
Since you are using Jetty as standalone server, you have to define RESTEasy validation providers where you define ServletContextHandler. Note that in standalone server there is no container to scan for #Provider classes and to activate them, so you must do it manually.
I expect that you create and start your server app something like:
//create a server listening at some port
Server server= new Server(port);
//add server handlers
HandlerList handlers= new HandlerList();
initHandlers(handlers);
server.setHandler(handlers);
//start the server
server.start();
In initHandlers you must have defined your RESTEasy support:
public void initHandlers(List<HandlerList> handlers) {
//define root context handler
ServletContextHandler servletContextHandler= new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath("/");
handlers.addHandler(servletContextHandler);
//define RESTEasy handler
ServletHolder restServlet= new ServletHolder(new HttpServlet30Dispatcher());
//since this is a standalone server, somewhere you have to define RESTful services and Singletons
restServlet.setInitParameter("javax.ws.rs.Application", "com.exampleapp.MyRestApplication");
restServlet.setInitParameter("resteasy.servlet.mapping.prefix", "rest");
servletContextHandler.addServlet(restServlet, "rest/*");
}
So what is left to do now is to add Validation provider as init parameter:
restServlet.setInitParameter("resteasy.providers", "org.jboss.resteasy.plugins.validation.ValidatorContextResolver,org.jboss.resteasy.api.validation.ResteasyViolationExceptionMapper");
On this link I tried to find the name of the validator providers: https://docs.jboss.org/resteasy/docs/3.0.4.Final/userguide/html/Validation.html
RESTEasy obtains a bean validation implemenation by looking in the available META-INF/services/javax.ws.rs.Providers files for an implementation of ContextResolver
So it does not say what, but says where. Now open the "resteasy-hibernatevalidator-provider-3...*.jar (from Eclipse -> Maven dependencies or manually unzip) and look into META-INF/services/javax.ws.rs.ext.Providers It says:
org.jboss.resteasy.plugins.validation.hibernate.ValidatorContextResolver
org.jboss.resteasy.api.validation.ResteasyViolationExceptionMapper
If you don't have this dependency, then add it to your pom file:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-hibernatevalidator-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
One more note: that at the same place where you described validation providers, you also add other providers, if you happen to need them (such as JacksonJaxbJson, etc).
I have a web-app that requires two settings:
A JDBC datasource
A string token
I desperately want to be able to deploy one .war to various different containers (jetty,tomcat,gf3 minimum) and configure these settings at application level within the container.
My code does this:
InitialContext ctx = new InitialContext();
Context envCtx = (javax.naming.Context) ctx.lookup("java:comp/env");
token = (String)envCtx.lookup("token");
ds = (DataSource)envCtx.lookup("jdbc/datasource")
Let's assume I've used the glassfish management interface to create two jdbc resources: jdbc/test-datasource and jdbc/live-datasource which connect to different copies of the same schema, on different servers, different credentials etc. Say I want to deploy this to glassfish with and point it at the test datasource, I might have this in my sun-web.xml:
...
<resource-ref>
<res-ref-name>jdbc/datasource</res-ref-name>
<jndi-name>jdbc/test-datasource</jndi-name>
</resource-ref>
...
but
sun-web.xml goes inside my war, right?
surely there must be a way to do this through the management interface
Am I even trying to do the right thing? Do other containers make this any easier? I'd be particularly interested in how jetty 7 handles this since I use it for development.
EDIT Tomcat has a reasonable way to do this:
Create $TOMCAT_HOME/conf/Catalina/localhost/webapp.xml with:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true">
<!-- String resource -->
<Environment name="token" value="value of token" type="java.lang.String" override="false" />
<!-- Linking to a global resource -->
<ResourceLink name="jdbc/datasource1" global="jdbc/test" type="javax.sql.DataSource" />
<!-- Derby -->
<Resource name="jdbc/datasource2"
type="javax.sql.DataSource"
auth="Container"
driverClassName="org.apache.derby.jdbc.EmbeddedDataSource"
url="jdbc:derby:test;create=true"
/>
<!-- H2 -->
<Resource name="jdbc/datasource3"
type="javax.sql.DataSource"
auth="Container"
driverClassName="org.h2.jdbcx.JdbcDataSource"
url="jdbc:h2:~/test"
username="sa"
password=""
/>
</Context>
Note that override="false" means the opposite. It means that this setting can't be overriden by web.xml.
I like this approach because the file is part of the container configuration not the war, but it's not part of the global configuration; it's webapp specific.
I guess I expect a bit more from glassfish since it is supposed to have a full web admin interface, but I would be happy enough with something equivalent to the above.
For GF v3, you may want to try leveraging the --deploymentplan option of the deploy subcommand of asadmin. It is discussed on the man page for the deploy subcommand.
We had just this issue when migrating from Tomcat to Glassfish 3. Here is what works for us.
In the Glassfish admin console, configure datasources (JDBC connection pools and resources) for DEV/TEST/PROD/etc.
Record your deployment time parameters (in our case database connect info) in properties file. For example:
# Database connection properties
dev=jdbc/dbdev
test=jdbc/dbtest
prod=jdbc/dbprod
Each web app can load the same database properties file.
Lookup the JDBC resource as follows.
import java.sql.Connection;
import javax.sql.DataSource;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* #param resourceName the resource name of the connection pool (eg jdbc/dbdev)
* #return Connection a pooled connection from the data source
* associated with resourceName
* #throws NamingException will be thrown if resource name is not found
*/
public Connection getDatabaseConnection(String resourceName)
throws NamingException, SQLException {
Context initContext = new InitialContext();
DataSource pooledDataSource = (DataSource) initContext.lookup(resourceName);
return pooledDataSource.getConnection();
}
Note that this is not the usual two step process involving a look up using the naming context "java:comp/env." I have no idea if this works in application containers other than GF3, but in GF3 there is no need to add resource descriptors to web.xml when using the above approach.
I'm not sure to really understand the question/problem.
As an Application Component Provider, you declare the resource(s) required by your application in a standard way (container agnostic) in the web.xml.
At deployment time, the Application Deployer and Administrator is supposed to follow the instructions provided by the Application Component Provider to resolve external dependencies (amongst other things) for example by creating a datasource at the application server level and mapping its real JNDI name to the resource name used by the application through the use of an application server specific deployment descriptor (e.g. the sun-web.xml for GlassFish). Obviously, this is a container specific step and thus not covered by the Java EE specification.
Now, if you want to change the database an application is using, you'll have to either:
change the mapping in the application server deployment descriptor - or -
modify the configuration of the existing datasource to make it points on another database.
Having an admin interface doesn't really change anything. If I missed something, don't hesitate to let me know. And just in case, maybe have a look at this previous answer.
I am new to jboss and i have been asked to incorporate jboss connection pooling mechanism with an existing web application. Considering that a web application database layer is properly written i.e. all resultsets, statements and connections being closed properly when not needed, What all code changes i will have to make in my web app after i have configured the jboss datasource properly.
Can anybody please point me to a tutorial or a code sample which uses jboss datasource in a web app.
first create an xml file by name xxx-ds.xml and place this file in server/default/deploy/xxx-ds.xml
<datasources>
<local-tx-datasource>
<jndi-name>/jdbc/Exp</jndi-name>
<type-mapping>SQL</type-mapping>
<connection-url>jdbc:microsoft:sqlserver:// </connection-url>
<driver-class>com.microsoft.jdbc.sqlserver.SQLServerDriver</driver-class>
<user-name></user-name>
<password></password>
<min-pool-size>5</min-pool-size>
<max-pool-size>1000</max-pool-size>
</local-tx-datasource>
</datasources>
jboss-web.xml
<jboss-web>
<!-- <security-domain flushOnSessionInvalidation="false"/>-->
<!-- <context-root>/BSI</context-root>-->
<resource-ref>
<description>Database connection resource</description>
<res-ref-name>jdbc/Exp</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<jndi-name>java:/jdbc/Exp</jndi-name>
<res-auth>Container</res-auth>
</resource-ref>
</jboss-web>
web.xml
<resource-ref>
<description>Database connection resource</description>
<res-ref-name>jdbc/Exp</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
and now in your .java file
javax.naming.Context ctx1 = new javax.naming.InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource) ctx1.lookup("java:comp/env/jdbc/Exp");
con = ds.getConnection();
***** make sure that resource ref name should be same in all place
The pool in JBoss is all handled in the DataSource configuration. Here is the HowTo. The web app would have to do a JNDI lookup for the datasource to get the database connection rather than doing a direct JDBC URL, and then you will have pooling.
Transactions are another story, though.
EDIT: In response to your comment about how this affects the code, this is what it looks like:
String jndiPath = "java:DataSourceJNDIName"; //The exact prefix here has a lot to do with clustering, etc., but if you are using one JBoss instance standalone, this works.
Context ctx = new InitialContext();
DataSource ds = (DataSource) PortableRemoteObject.narrow(ctx.lookup(jndiPath), DataSource.class);
Connection c = ds.getConnection();
Technically speaking the PortableRemoteObject.narrow isn't necessary in a JBoss (4.2.2 anyway) single server configuration for sure, but it is more proper J2EE standard code, as general application servers don't have to return an object of the right type just for doing a Context.lookup.
The above doesn't cover the resource utilization and error handling issues. You are supposed to close that Context object when you are done with it, and of course the database connection, although JBoss will yell at you if you forget to close the database connection and the transaction ends, and close it for you.
Anyway, that Connection object is usable just as much as DriverManager.getConnection(url);
You don't have to change anything.
When you select the right kind of data source (local-tx-datasource / xa-datasource), connection handling and TX is done for you. In $JBoss/docs/examples/jca you will find templates for virtually every database, that you can just reuse.
If you are using XA, you need to configure Tx-recovery. See this posting on a how-to:
http://management-platform.blogspot.com/2008/11/transaction-recovery-in-jbossas.html (well, perhaps not a how-to in the standalone mode, but in conjunction with the Jopr source code).