I have an swing application that connects to a Jboss 7 AS.
Invoking some background threads causes a no such ejb error on client side.
Here is an example
package com.asf.capone.client.util;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.asf.capone.common.exception.AppException;
import ro.asf.capone.ejb.beans.security.SecurityController;
import ro.asf.capone.ejb.beans.security.SecurityControllerRemote;
public class TestJndi {
public static void main(final String[] args) throws AppException {
final Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
env.put("java.naming.provider.url", "remote://localhost:4447");
env.put("java.naming.security.credentials", "c4ca4238a0b923820dcc509a6f75849b");
env.put("java.naming.security.principal", "capone");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
env.put("jboss.naming.client.ejb.context", "true");
env.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
try {
final InitialContext ctx = new InitialContext(env);
System.out.println("ctx: " + ctx);
final SecurityController o = (SecurityControllerRemote) ctx.lookup(
"ejb:agency-ear/agency-ejb/SecurityControllerBean!ro.asf.capone.ejb.beans.security.SecurityControllerRemote");
System.out.println("1outcome: " + o.getServerTimeMillis());
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("2outcome: " + o.getServerTimeMillis());
}
}).start();
} catch (final NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The output for this is:
ctx: javax.naming.InitialContext#307f6b8c
1outcome: 1443465336127
Exception in thread "Thread-4" java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:agency-ear, moduleName:agency-ejb, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext#381dfddb
at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:754)
at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186)
at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:253)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:198)
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:181)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:144)
at com.sun.proxy.$Proxy2.getServerTimeMillis(Unknown Source)
at com.asf.capone.client.util.TestJndi$1.run(TestJndi.java:36)
at java.lang.Thread.run(Thread.java:745)
I am missing something that should allow me to get the same output on both calls but I cannot figure what is the problem. Thanks!
It looks like this doesn't work on that version of Jboss (they've changed the remote) because my initial code worked in Jboss 7.3.0. My current Jboss version is JBoss EAP 6.4.0.GA (AS 7.5.0.Final-redhat-21)
The code that works now is:
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.ejb.client.ContextSelector;
import org.jboss.ejb.client.EJBClientConfiguration;
import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration;
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector;
import ro.asf.capone.ejb.beans.security.SecurityControllerRemote;
public class AppJboss {
public static void main(String[] args) throws NamingException {
System.out.println("Hello World!");
final String lookup = "ejb:agency-ear/agency-ejb//SecurityControllerBean!ro.asf.capone.ejb.beans.security.SecurityControllerRemote";
final Properties clientProperties = new Properties();
clientProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS",
"JBOSS-LOCAL-USER");
clientProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT",
"false");
clientProperties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
clientProperties.put("remote.connections", "default");
clientProperties.put("endpoint.name", "client-endpoint");
clientProperties.put("remote.connection.default.port", "4447");
clientProperties.put("remote.connection.default.host", "127.0.0.1");
clientProperties.put("remote.connection.default.username", "capone");
clientProperties.put("remote.connection.default.password", "c4ca4238a0b923820dcc509a6f75849b");
clientProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS",
"false");
final EJBClientConfiguration ejbClientConfiguration = new PropertiesBasedEJBClientConfiguration(
clientProperties);
final ContextSelector<EJBClientContext> contextSelector = new ConfigBasedEJBClientContextSelector(
ejbClientConfiguration);
EJBClientContext.setSelector(contextSelector);
final Properties properties = new Properties();
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(properties);
final SecurityControllerRemote myBean = (SecurityControllerRemote) context.lookup(lookup);
final long result = myBean.getServerTimeMillis();
System.out.println("result " + result);
new Thread(new Runnable() {
public void run() {
final long result = myBean.getServerTimeMillis();
System.out.println(result);
}
}).start();
}
}
The client library was taken from jboss/bin/client/jboss-client.jar
The same code works in Wildfly also, just with the change of port and client library. Hope this helps others.
Related
I'm having an issue with adding a user to my LDAP server in Java.
Here's what my code looks like
import java.util.Hashtable;
import java.util.Properties;
import java.util.jar.Attributes;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class LdapProgram {
public static void main(String[] args) {
String dn = "";
String password = "";
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
properties.put(Context.PROVIDER_URL, "ldap://127.0.0.1");
properties.put(Context.SECURITY_AUTHENTICATION,"none");
properties.put(Context.SECURITY_PRINCIPAL,password);
properties.put(Context.SECURITY_CREDENTIALS,dn);
// TODO code application logic here
// entry's DN
String entryDN = "uid=test_user,ou=people,dc=test123,dc=com";
// entry's attributes
Attribute cn = new BasicAttribute("cn", "tester");
Attribute uid = new BasicAttribute("uid", "tester");
Attribute gecos = new BasicAttribute("gecos", "test");
Attribute oc = new BasicAttribute("objectClass");
oc.add("top");
oc.add("person");
oc.add("organizationalPerson");
oc.add("inetOrgPerson");
DirContext ctx = null;
try {
// get a handle to an Initial DirContext
ctx = new InitialDirContext(properties);
// build the entry
BasicAttributes entry = new BasicAttributes();
entry.put(cn);
entry.put(uid);
entry.put(gecos);
entry.put(oc);
// Add the entry
ctx.createSubcontext(entryDN, entry);
// System.out.println( "AddUser: added entry " + entryDN + ".");
} catch (NamingException e) {
System.err.println("AddUser: error adding entry.\n" + e);
}
}
}
Here is the error code I get: javax.naming.AuthenticationNotSupportedException: [LDAP: error code 8 - modifications require authentication]; remaining name 'uid=test_user,ou=people,dc=test123,dc=com'
I'm not understanding why it's saying it requires authentication when I'm already binded to the server with the admin user and password.
I am using Vertx 3.6.3. I am trying to run an HTTPS server verticle, but unfortunately, verticle is not getting deployed. Could you please let me know where I am doing it wrong?
Here is my verticle:
HTTPSVerticle:
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.PfxOptions;
public class HTTPSVerticle extends AbstractVerticle {
#Override
public void start(Future<Void> httpsServerStarted) throws Exception {
int port = config().getJsonObject("http", new JsonObject()).getInteger("port", 8000);
boolean useSsl = config().getJsonObject("http", new JsonObject()).getBoolean("useSsl", false);
String sslCertPath = config().getJsonObject("http", new JsonObject()).getString("sslCertPath", "");
String sslCertPassword = config().getJsonObject("http", new JsonObject()).getString("sslCertPassword", "");
HttpServerOptions httpServerOptions = new HttpServerOptions();
System.out.println(useSsl);
if (useSsl)
httpServerOptions
.setSsl(true)
//.setClientAuth(ClientAuth.REQUIRED)
.setPfxTrustOptions(
new PfxOptions().setPath(sslCertPath).setPassword(sslCertPassword)
);
vertx.createHttpServer(httpServerOptions).requestHandler(httpReq -> {
httpReq.response().end("Hello encrypted world");
}).listen(port, fut -> {
if (fut.succeeded()) {
System.out.println("Verticle now listening on port: " + port);
httpsServerStarted.complete();
}
else {
httpsServerStarted.fail(fut.cause());
System.out.println("Error while starting HTTP server");
}
});
}
}
Here is my test case:
TestHTTPSVerticle:
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.unit.Async;
import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(VertxUnitRunner.class)
public class TestHTTPSVerticle {
private static Vertx vertx;
#BeforeClass
public static void setUp(TestContext context) {
DeploymentOptions opts = new DeploymentOptions()
.setConfig(new JsonObject().put("http", new JsonObject()
.put("useSsl", true)
.put("sslCertPath", "test.pfx")
.put("sslCertPassword", "abcd")));
vertx = Vertx.vertx();
vertx.deployVerticle(HTTPSVerticle.class.getName(), opts, context.asyncAssertSuccess());
}
#AfterClass
public static void tearDown(TestContext context) {
vertx.close(context.asyncAssertSuccess());
}
#Test
public void testHttpsServerMessage(TestContext context) {
Async async = context.async();
System.out.println("Connecting to server...");
vertx.createHttpClient().get(8000, "localhost", "/loremipsum", respHandler -> respHandler.bodyHandler(respBody -> {
System.out.println(respBody);
context.assertTrue(respBody.toString().equals("Hello encrypted world"));
async.complete();
})).end();
}
}
Its not letting me submit it without elaborating, so redundant elaboration follows:
I am using vertx config mechanism to fetch port, useSsl, sslCertPath and sslCertPassword
I am using HttpServerOptions for configuring SSL settings for http server
When server is started successfully, it should print Verticle now listening on port: 8000
In case, server fails to start, it should print Error while starting HTTP server
But, It never invokes listen's handler with AsyncResult.
I am trying to write an integration test to spin up jetty server locally and then use client to communicate with the rest URI and call the business logic downstream. However, when I start my jetty server it does not relinquish the control, so my client is not executed. So I used threading to start my jetty in a different thread, however, the thread finishes before my client call, it says connection refused. Any approach I can take?
#Test
public void testPerform() {
final JettyServer jettyServer = JettyServer.create();
jettyServer.buildJettyServer(ServletContextHandler.SESSIONS, "/", 8080, TestResource.class);
Runnable runnable = new Runnable()
{
#Override
public void run()
{
jettyServer.start();
}
};
new Thread(runnable).start();
final javax.ws.rs.client.Client client = ClientBuilder.newClient();
final Response response = client.target("http://localhost:8080/test").request().post(Entity.text(""));
jettyServer.stop();
}
Skip the Runnable, skip the new Thread(runnable).start()
The call jettyServer.start() starts the server on its own thread (along with all of the other threads that the server needs.
For a basic example of junit and jetty ...
#Test
public void testGet() throws Exception
{
// Create Server
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir"));
defaultServ.setInitParameter("dirAllowed","true");
context.addServlet(defaultServ,"/");
server.setHandler(context);
// Start Server
server.start();
// Test GET
HttpURLConnection http = (HttpURLConnection)new URL("http://localhost:8080/").openConnection();
http.connect();
assertThat("Response Code", http.getResponseCode(), is(HttpStatus.OK_200));
// Stop Server
server.stop();
}
The #Before and #After junit annotations can also be used. This will start the server before each #Test and stop the server after.
package jetty;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.net.HttpURLConnection;
import java.net.URL;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JUnitBeforeAfterJettyTest
{
private Server server;
#Before
public void startJetty() throws Exception
{
// Create Server
server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir"));
defaultServ.setInitParameter("dirAllowed","true");
context.addServlet(defaultServ,"/");
server.setHandler(context);
// Start Server
server.start();
}
#After
public void stopJetty()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Test
public void testGet() throws Exception
{
// Test GET
HttpURLConnection http = (HttpURLConnection)new URL("http://localhost:8080/").openConnection();
http.connect();
assertThat("Response Code", http.getResponseCode(), is(HttpStatus.OK_200));
}
}
For the best approach, you can also use the #BeforeClass and #AfterClass techniques, along with auto-binding to an open port. This will only start the server once, per Test Class, run all of the #Test methods, then stop the server once at the end.
package jetty;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class JUnitBeforeAfterClassJettyTest
{
private static Server server;
private static URI serverUri;
#BeforeClass
public static void startJetty() throws Exception
{
// Create Server
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0); // auto-bind to available port
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir"));
defaultServ.setInitParameter("dirAllowed","true");
context.addServlet(defaultServ,"/");
server.setHandler(context);
// Start Server
server.start();
// Determine Base URI for Server
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("http://%s:%d/",host,port));
}
#AfterClass
public static void stopJetty()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Test
public void testGet() throws Exception
{
// Test GET
HttpURLConnection http = (HttpURLConnection) serverUri.resolve("/").toURL().openConnection();
http.connect();
assertThat("Response Code", http.getResponseCode(), is(HttpStatus.OK_200));
}
}
I am using JMX to get number of threads in Weblogic but an error happens.
This is my code:
import java.util.Hashtable;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MaximizeAction;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
public class JMXClient {
private static MBeanServerConnection connection;
private static JMXConnector connector;
private static ObjectName service;
//Update correct port
private static String port = "7001";
//Update localhost if server is accessed remotely
private static String url = "t3://localhost:7001";
// Update hostname if server is accessed remotely
private static String hostname = "localhost";
private static String username = "weblogic";
private static String password = "12345678";
// server name can differ from host name
private static String serverName = "AdminServer";
/*
* Initialize connection to the Runtime MBean Server
*/
private static void init() throws IOException, MalformedURLException {
String protocol = "t3";
Integer portInteger = Integer.valueOf(port);
int port = portInteger.intValue();
String jndiroot = "/jndi/";
String mserver = "weblogic.management.mbeanservers.runtime";
//JMXServiceURL serviceURL = new JMXServiceURL(url);
JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port, jndiroot + mserver);
Hashtable env = new Hashtable();
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.runtime.JRockitRuntimeMBean");
connector = JMXConnectorFactory.connect(serviceURL, env);
connection = connector.getMBeanServerConnection();
try {
service = new ObjectName("com.bea:Name="+serverName + ",Type=ServerRuntime");
} catch (MalformedObjectNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void getTotalNumberOfThreads() {
try {
init();
Long totalNumberOfThreads = (Long) connection.getAttribute(service,"TotalNumberOfThreads");
System.out.println("totalNumberOfThreads is: " + totalNumberOfThreads);
connection.invoke(service, "start", new Object[] {}, new String[] {});
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// Invoke required methods
JMXClient.getTotalNumberOfThreads();
}
}
The error is :
java.net.MalformedURLException: Unsupported protocol: t3
at javax.management.remote.JMXConnectorFactory.newJMXConnector(Unknown Source)
at javax.management.remote.JMXConnectorFactory.connect(Unknown Source)
I don't know why this happens.
When I am using weblogic.management.remote to get the state of application server, everything is ok, but for the number of threads, it doesn't answer.
I put all these five jars in classpath to solved similar issue:
<include name="wlclient.jar" />
<include name="wljmsclient.jar" />
<include name="wls-api.jar"/>
<include name="wljmxclient.jar"/>
<include name="wlconnector.jar"/>
Actually you need the following jars only:
\Oracle_Home\wlserver\server\lib\wljmxclient.jar
\Oracle_Home\wlserver\server\lib\weblogic.jar
it works with me against default and sql provider.
I got the same issue in WLS12.2.1.3, fixed after adding only the /wlserver/server/lib/wlthint3client.jar file to the libraries.
This has been most likely answered earlier, but all my searches did not get me a definite answer. What I've got is a Java application that currently uses ssh keys to run a script on a remote machine and save the results. I'm in the process of changing this to a Kerberos authentication using keytabs. I have the keytab set up and tested it using a perl script. If someone could point me to examples that tell me how to use kerberos keytabs in a Java application, that would be very helpful.
Thanks,
Kiran
Here's a full implementation of using a keytab in Java.
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.security.Principal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class SecurityUtils {
public static class LoginConfig extends Configuration {
private String keyTabLocation;
private String servicePrincipalName;
private boolean debug;
public LoginConfig(String keyTabLocation, String servicePrincipalName, boolean debug) {
this.keyTabLocation = keyTabLocation;
this.servicePrincipalName = servicePrincipalName;
this.debug = debug;
}
#Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
HashMap<String, String> options = new HashMap<String, String>();
options.put("useKeyTab", "true");
options.put("keyTab", this.keyTabLocation);
options.put("principal", this.servicePrincipalName);
options.put("storeKey", "true");
options.put("doNotPrompt", "true");
if (this.debug) {
options.put("debug", "true");
}
options.put("isInitiator", "false");
return new AppConfigurationEntry[]{new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options),};
}
}
public static Subject loginAs(String keyTabLocation, String servicePrincipal) {
try {
LoginConfig loginConfig = new LoginConfig(keyTabLocation, servicePrincipal, true);
Set<Principal> princ = new HashSet<Principal>(1);
princ.add(new KerberosPrincipal(servicePrincipal));
Subject sub = new Subject(false, princ, new HashSet<Object>(), new HashSet<Object>());
LoginContext lc;
lc = new LoginContext("", sub, null, loginConfig);
lc.login();
return lc.getSubject();
} catch (LoginException e) {
e.printStackTrace();
}
return null;
}
}
The loginAs method will return you a Subject which can be used to execute a privileged action:
result = Subject.doAs(subject,
new PrivilegedExceptionAction<NamingEnumeration<SearchResult>>() {
public NamingEnumeration<SearchResult> run() throws NamingException {
return context.search(directoryBase, filterBuilder.toString(), searchCtls);
}
});