How can you store credentials in a JNDI lookup? - glassfish

I have an app with several properties files, and I was curious if it'd be easier to store these username/password/server-url-to-login-to combos in a JNDI lookup instead of this clear text file in a .jar.
There are a couple questions:
Can you store credentials that aren't databases using JNDI?
How do you configure a new JNDI resource to store these properties?
How would you retrieve these properties from the resource?
Most of the documentation I read was how to set up JNDI for database connections, and for my use, I'm not connecting to any databases, but instead different kinds of web services using different authentication schemes (SOAP user/password in request message, HTTP Basic, headers, SSL, etc.).

The answers to your questions:
Can you store credentials that aren't databases using JNDI?
Yes.
How do you configure a new JNDI resource to store these properties?
If you are using Glassfish 2 you have to create your custom PropertiesObjectFactory class to handle JNDI properties of java.util.Porperties.
For e.g. PropertiesObjectFactory class could look like this:
public class PropertiesObjectFactory implements Serializable, ObjectFactory {
public static final String FILE_PROPERTY_NAME = "org.glassfish.resources.custom.factory.PropertiesFactory.fileName";
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
Reference ref = (Reference) obj;
Enumeration<RefAddr> refAddrs = ref.getAll();
String fileName = null;
Properties fileProperties = new Properties();
Properties properties = new Properties();
while (refAddrs.hasMoreElements()) {
RefAddr addr = refAddrs.nextElement();
String type = addr.getType();
String value = (String) addr.getContent();
if (type.equalsIgnoreCase(FILE_PROPERTY_NAME)) {
fileName = value;
} else {
properties.put(type, value);
}
}
if (fileName != null) {
File file = new File(fileName);
if (!file.isAbsolute()) {
file = new File(System.getProperty("com.sun.aas.installRoot") + File.separator + fileName);
}
try {
if (file.exists()) {
try {
FileInputStream fis = new FileInputStream(file);
if (fileName.toUpperCase().endsWith("XML")) {
fileProperties.loadFromXML(fis);
} else {
fileProperties.load(fis);
}
} catch (IOException ioe) {
throw new IOException("IO Exception during properties load : " + file.getAbsolutePath());
}
} else {
throw new FileNotFoundException("File not found : " + file.getAbsolutePath());
}
} catch (FileNotFoundException fnfe) {
throw new FileNotFoundException("File not found : " + file.getAbsolutePath());
}
}
fileProperties.putAll(properties);
return fileProperties;
}
}
Make a jar of that class, add it into glassfish global classpath. It would be: /glassfish/domains/domain1/lib and then you can specify it as a factory class in your JNDI properties configuration.
Glassfish 3 already have properties factory class. It is set into: org.glassfish.resources.custom.factory.PropertiesFactory.
Open glassfish admin console and navigate to: Resources -> JNDI -> Custom Resources, click "New", provide a JNDI name, for e.g: jndi/credentials, choose a resource type java.util.Properties, specify Factory class: org.glassfish.resources.custom.factory.PropertiesFactory, then click "Add property", specify name for e.g: testUsernameName and in value column testUsernameValue. Click OK and that is all, you have configured JNDI resource. You can add as many properties as you like to this: jndi/credentials resource.
Don't forget to restart app server when you done creating resources.
How would you retrieve these properties from the resource?
public Properties getProperties(String jndiName) {
Properties properties = null;
try {
InitialContext context = new InitialContext();
properties = (Properties) context.lookup(jndiName);
context.close();
} catch (NamingException e) {
LOGGER.error("Naming error occurred while initializing properties from JNDI.", e);
return null;
}
return properties;
}
Example how to get the property:
String username = someInstance.getProperties("jndi/credentials").getProperty("testUsernameName");
Your username would be: testUsernameValue.
When you call this method in your application provide a JNDI name you configured in your application server: jndi/credentials. If you have mapped resources in deployment descriptor you have to use: java:comp/env/jndi/credentials.
If you want to do the same using Spring:
<jee:jndi-lookup id="credentials"
jndi-name="jndi/credentials"/>
Well I hope thats it. Hope this helps.

Related

How to connect to FTPS server with data connection using same TLS session from Apache Camel using custom FTPSClient?

I would like to send files to FTPS server using Apache Camel. The problem is that this FTPS server requires that the TLS/SSL session is to be reused for the data connection. And I can't set 'TLSOptions NoSessionReuseRequired' option for security reason to solve the issue.
As far as I know, Apache Camel uses Apache Common Net class FTPSClient internally to communicate to FTPS servers and Apache Common Net doesn't support this feature as described here
So I has implemented this workaround. Here is code of my custom FTPSClient:
public class SSLSessionReuseFTPSClient extends FTPSClient {
// adapted from: https://trac.cyberduck.io/changeset/10760
#Override
protected void _prepareDataSocket_(final Socket socket) throws IOException {
if (socket instanceof SSLSocket) {
final SSLSession session = ((SSLSocket) _socket_).getSession();
final SSLSessionContext context = session.getSessionContext();
try {
final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
putMethod.setAccessible(true);
// final Method getHostMethod = socket.getClass().getDeclaredMethod("getHost");
Method getHostMethod;
try {
getHostMethod = socket.getClass().getDeclaredMethod("getPeerHost");
} catch (NoSuchMethodException e) {
getHostMethod = socket.getClass().getDeclaredMethod("getHost");
}
getHostMethod.setAccessible(true);
Object host = getHostMethod.invoke(socket);
final String key = String.format("%s:%s", host, String.valueOf(socket.getPort()))
.toLowerCase(Locale.ROOT);
putMethod.invoke(cache, key, session);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
It works brilliantly as standalone FTPS client in JDK 8 and JDK 11 as shown:
public class FTPSDemoClient {
public static void main(String[] args) throws IOException {
System.out.println("Java version is: " + System.getProperty("java.version"));
System.out.println("Java vendor is: " + System.getProperty("java.vendor"));
final SSLSessionReuseFTPSClient ftps = new SSLSessionReuseFTPSClient();
System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
System.setProperty("jdk.tls.client.enableSessionTicketExtension", "false");
System.setProperty("jdk.tls.client.protocols", "TLSv1,TLSv1.1,TLSv1.2");
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
//System.setProperty("javax.net.debug", "all");
ftps.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
ftps.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
ftps.connect("my_ftps_server");
System.out.println("Connected to server");
ftps.login("user", "password");
System.out.println("Loggeded to server");
ftps.setFileType(FTP.BINARY_FILE_TYPE);
// Use passive mode as default because most of us are
// behind firewalls these days.
ftps.enterLocalPassiveMode();
ftps.setUseEPSVwithIPv4(true);
// Set data channel protection to private
ftps.execPROT("P");
for (final String s : ftps.listNames("directory1/directory2")) {
System.out.println(s);
}
// send file
try (final InputStream input = new FileInputStream("C:\\testdata\\olympus2.jpg")) {
ftps.storeFile("directory1/directory2/olympus2.jpg", input);
}
// receive file
try (final OutputStream output = new FileOutputStream("C:\\testdata\\ddd.txt")) {
ftps.retrieveFile(""directory1/directory2/ddd.txt", output);
}
ftps.logout();
if (ftps.isConnected()) {
try {
ftps.disconnect();
} catch (final IOException f) {
// do nothing
}
}
}
}
Now I am ready to use this custom FTPSClient in my Apache Camel route, first I create custom FTPSClient instance and make it available for Apache Camel:
public final class MyFtpClient {
public static void main(String[] args) {
RouteBuilder routeBuilder = new MyFtpClientRouteBuilder();
System.out.println("Java version is: " + System.getProperty("java.version"));
System.out.println("Java vendor is: " + System.getProperty("java.vendor"));
System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
System.setProperty("jdk.tls.client.enableSessionTicketExtension", String.valueOf(false));
System.setProperty("jdk.tls.client.protocols", "TLSv1,TLSv1.1,TLSv1.2");
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
SSLSessionReuseFTPSClient ftps = new SSLSessionReuseFTPSClient();
ftps.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
// ftps.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
ftps.setRemoteVerificationEnabled(false);
ftps.setUseEPSVwithIPv4(true);
SimpleRegistry registry = new SimpleRegistry();
registry.bind("FTPClient", ftps);
// tell Camel to use our SimpleRegistry
CamelContext ctx = new DefaultCamelContext(registry);
try {
ctx.addRoutes(routeBuilder);
ctx.start();
Thread.sleep(5 * 60 * 1000);
ctx.stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
And use it in Apache Camel Route:
public class MyFtpClientRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// lets shutdown faster in case of in-flight messages stack up
getContext().getShutdownStrategy().setTimeout(10);
from("ftps://my_ftps_server:21/directory1/directory2?username=user&password=RAW(password)"
+ "&localWorkDirectory=/tmp&autoCreate=false&passiveMode=true&binary=true&noop=true&resumeDownload=true"
+ "&bridgeErrorHandler=true&throwExceptionOnConnectFailed=true&maximumReconnectAttempts=0&transferLoggingLevel=OFF"
+ "&readLock=changed&disconnect=true&ftpClient=#FTPClient") // #FTPClient
.to("file://c:/testdata?noop=true&readLock=changed")
.log("Downloaded file ${file:name} complete.");
// use system out so it stand out
System.out.println("*********************************************************************************");
System.out.println("Use ctrl + c to stop this application.");
System.out.println("*********************************************************************************");
}
}
And it works!
But, when I add another route in the same java code by adding second from clause like this:
from("ftps://my_ftps_server/directory1/directory2?username=user&password=RAW(password)"
+ "&localWorkDirectory=/tmp&autoCreate=false&passiveMode=true&binary=true&noop=true&resumeDownload=true"
+ "&bridgeErrorHandler=true&throwExceptionOnConnectFailed=true&maximumReconnectAttempts=0&transferLoggingLevel=OFF"
+ "&readLock=changed&disconnect=true&ftpClient=#FTPClient") // #FTPClient
.to("file://c:/testdata?noop=true&readLock=changed")
.log("Downloaded file ${file:name} complete.");
from("file://c:/testdata?noop=true&readLock=changed&delay=30s")
.to("ftps://my_ftps_server/directory1/directory2?username=user&password=RAW(password)"
+ "&localWorkDirectory=/tmp&autoCreate=false&passiveMode=true&binary=true&noop=true&resumeDownload=true"
+ "&bridgeErrorHandler=true&throwExceptionOnConnectFailed=true&maximumReconnectAttempts=0&transferLoggingLevel=OFF"
+ "&readLock=changed&disconnect=true&stepwise=false&ftpClient=#FTPClient") // changed from FTPClient to FTPClient1
.log("Upload file ${file:name} complete.");
it ruins my code, it throws exception:
org.apache.camel.component.file.GenericFileOperationFailedException: File operation failed: null Socket is closed. Code: 226
...
Caused by: java.net.SocketException: Socket is closed
at java.net.Socket.setSoTimeout(Socket.java:1155) ~[?:?]
at sun.security.ssl.BaseSSLSocketImpl.setSoTimeout(BaseSSLSocketImpl.java:637) ~[?:?]
at sun.security.ssl.SSLSocketImpl.setSoTimeout(SSLSocketImpl.java:74) ~[?:?]
at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:426) ~[commons-net-3.8.0.jar:3.8.0]
at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:668) ~[commons-net-3.8.0.jar:3.8.0]
at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:658) ~[commons-net-3.8.0.jar:3.8.0]
at org.apache.commons.net.ftp.FTPSClient._connectAction_(FTPSClient.java:221) ~[commons-net-3.8.0.jar:3.8.0]
at org.apache.commons.net.SocketClient._connect(SocketClient.java:254) ~[commons-net-3.8.0.jar:3.8.0]
at org.apache.commons.net.SocketClient.connect(SocketClient.java:212) ~[commons-net-3.8.0.jar:3.8.0]
at org.apache.camel.component.file.remote.FtpOperations.doConnect(FtpOperations.java:125) ~[camel-ftp-3.4.1.jar:3.4.1]
Files, anyway are transferred to and from FTPS server by Apache Camel.
Interesting thing, when I don't share my custom FTPSClient and use one instance exactly for one route like this:
SSLSessionReuseFTPSClient ftps = new SSLSessionReuseFTPSClient();
...
SSLSessionReuseFTPSClient ftps1 = new SSLSessionReuseFTPSClient();
...
SimpleRegistry registry = new SimpleRegistry();
registry.bind("FTPClient", ftps);
registry.bind("FTPClient1", ftps1);
from("ftps://my_ftps_server/directory1/directory2?username=user&password=RAW(password)"
+ "&localWorkDirectory=/tmp&autoCreate=false&passiveMode=true&binary=true&noop=true&resumeDownload=true"
+ "&bridgeErrorHandler=true&throwExceptionOnConnectFailed=true&maximumReconnectAttempts=0&transferLoggingLevel=OFF"
+ "&readLock=changed&disconnect=true&ftpClient=#FTPClient") // #FTPClient
.to("file://c:/testdata?noop=true&readLock=changed")
.log("Downloaded file ${file:name} complete.");
from("file://c:/testdata?noop=true&readLock=changed&delay=30s")
.to("ftps://my_ftps_server/directory1/directory2?username=user&password=RAW(password)"
+ "&localWorkDirectory=/tmp&autoCreate=false&passiveMode=true&binary=true&noop=true&resumeDownload=true"
+ "&bridgeErrorHandler=true&throwExceptionOnConnectFailed=true&maximumReconnectAttempts=0&transferLoggingLevel=OFF"
+ "&readLock=changed&disconnect=true&stepwise=false&ftpClient=#FTPClient1")
.log("Upload file ${file:name} complete.");
it works perfectly!
So, I have couple of questions:
Why does Apache Camel (I mean Apache Common Net) developers refuse (or can't) to add usage of same TLS session functionality to FTPSClient class since 2011?
Am I the only person who uses Apache Camel to work with FTPS server with data connection using same TLS session? I haven't managed to find solution anywhere.
Is it possible to force Apache Camel not to share custom FTPSClient instance what, I suppose is the root of the problem, but to create new instance of FTPSClient every time then route are processed? My solution doesn't seem elegant.
What is wrong in my custom FTPSClient implementation that leads to this error then I use instance of this class in Apache Camel? Standard FTPClient hasn't this issue, of course.

How can I get username and name of active local changes from git project in IntelliJ plugin

I would like to create a plugin that would use a username and name of active local changes in git project. Can I get this information from action or context?
I found a solution.
For git username:
private static String getGitUsername() {
try {
Process process = Runtime.getRuntime().exec("git config user.name");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
return reader.readLine();
} catch (Exception e) {
return DEFAULT_USER;
}
}
For name of active local changes:
private static String getChangeListName(Project project) {
return ChangeListManager.getInstance(project).getDefaultListName();
}

Has anyone ever got WS-Trust to work in JBoss 7?

I've literally tried everything under the sun to get token based WS-Trust Web Services to work, to no avail. I can obtain a token from an STS, but the life of me, I can not figure out how make the WS server secure and accessible from the outside using a token.
So what I would love to know, is if anyone has ever got this to work on JBoss 7. I'm not interested in "this and that on jboss should give you some information". Been there done that - doesn't work. Have YOU been able to get it to work?
I looked at picketlink to secure web services using SAML but it appears to be exposing the SAML authentication using a JAAS security context. So instead I just wrote a custom handler using the picketlink API to secure the WS. The handler essentially does the same thing (i.e. saml assertion expiration and digital signature validation check) as the SAMLTokenCertValidatingCommonLoginModule available in picketlink jars but passes the SAML attributes into WS message context instead of passing it along as a JAAS security context.
Find below the code snippet.
See org.picketlink.identity.federation.bindings.jboss.auth.SAMLTokenCertValidatingCommonLoginModule
class of the picketlink-jbas-common source for implementation of methods getX509Certificate, validateCertPath used in the custom handler.
public class CustomSAML2Handler<C extends LogicalMessageContext> implements SOAPHandler {
protected boolean handleInbound(MessageContext msgContext) {
logger.info("Handling Inbound Message");
String assertionNS = JBossSAMLURIConstants.ASSERTION_NSURI.get();
SOAPMessageContext ctx = (SOAPMessageContext) msgContext;
SOAPMessage soapMessage = ctx.getMessage();
if (soapMessage == null)
throw logger.nullValueError("SOAP Message");
// retrieve the assertion
Document document = soapMessage.getSOAPPart();
Element soapHeader = Util.findOrCreateSoapHeader(document.getDocumentElement());
Element assertion = Util.findElement(soapHeader, new QName(assertionNS, "Assertion"));
if (assertion != null) {
AssertionType assertionType = null;
try {
assertionType = SAMLUtil.fromElement(assertion);
if (AssertionUtil.hasExpired(assertionType))
throw new RuntimeException(logger.samlAssertionExpiredError());
} catch (Exception e) {
logger.samlAssertionPasingFailed(e);
}
SamlCredential credential = new SamlCredential(assertion);
if (logger.isTraceEnabled()) {
logger.trace("Assertion included in SOAP payload: " + credential.getAssertionAsString());
}
try {
validateSAMLCredential(credential, assertionType);
ctx.put("roles",AssertionUtil.getRoles(assertionType, null));
ctx.setScope("roles", MessageContext.Scope.APPLICATION);
} catch (Exception e) {
logger.error("Error: " + e);
throw new RuntimeException(e);
}
} else {
logger.trace("We did not find any assertion");
}
return true;
}
private void validateSAMLCredential(SamlCredential credential, AssertionType assertion) throws LoginException, ConfigurationException, CertificateExpiredException, CertificateNotYetValidException {
// initialize xmlsec
org.apache.xml.security.Init.init();
X509Certificate cert = getX509Certificate(credential);
// public certificate validation
validateCertPath(cert);
// check time validity of the certificate
cert.checkValidity();
boolean sigValid = false;
try {
sigValid = AssertionUtil.isSignatureValid(credential.getAssertionAsElement(), cert.getPublicKey());
} catch (ProcessingException e) {
logger.processingError(e);
}
if (!sigValid) {
throw logger.authSAMLInvalidSignatureError();
}
if (AssertionUtil.hasExpired(assertion)) {
throw logger.authSAMLAssertionExpiredError();
}
}
}

Best practices for Run with elevated privelege

Among the two approaches which one is preferred with run with elevated privileges?
First Approach:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite curSite = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = curSite.OpenWeb(SPContext.Current.Web.ID))
{
try
{
web.AllowUnsafeUpdates = true;
\\ do your stuff
}
catch (Exception e)
{
}
finally
{
web.AllowUnsafeUpdates = false;
web.Dispose();
}
}
}
});
Second Approach:
SPSite oSite = SPContext.Current.Site;
SPWeb oWeb = SPContext.Current.Web;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite curSite = new SPSite(oSite.ID))
{
using (SPWeb web = curSite.OpenWeb(oWeb.ID))
{
try
{
web.AllowUnsafeUpdates = true;
\\ do your stuff
}
catch (Exception e)
{
}
finally
{
web.AllowUnsafeUpdates = false;
web.Dispose();
oWeb.Dispose();
oSite.Dispose();
}
}
}
});
Are any of them suspected to throw "The web being updated was changed by an external process" exception ?
First of all, you should make a call to SPWeb.ValidateFormDigest() or SPUtility.ValidateFormDigest() before elevating the code. This will get rid of unsafe update not allowed with GET request, and avoid you to setup the AllowUnsafeUpdate property.
Secondly, as Nigel Whatling mentioned, you are disposing context object in your second code. You don't have to dispose them. To be simple, only dispose object you are instantiating yourself. A code like yours can cause side effects, as other SharePoint component may require access to SPContext.Current.XX objects. This is probably the root of your issue.
Thirdly, as you are using the using construct, you don't have to call .Dispose() on the variable you set up in the using header. Actually, the role (and actually benefit) of the using construct is that you don't have to care to dispose the object. As soon as the block code exits, even if there was an exception, the .Dispose() method is called on your object.
To conclude, your code should be changed to that :
SPUtility.ValidateFormDigest();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite curSite = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = curSite.OpenWeb(SPContext.Current.Web.ID))
{
// Do stuff here
}
}
});
A side note: to elevate a code, you have two options. The one you use here (call to SPSecurity.RunWithElevatedPrivileges) or instantiating a new SPSite with the SystemAccount token :
using (SPSite curSite = new SPSite(
SPContext.Current.Site.ID,
SPContext.Current.Site.SystemAccount.UserToken
))
{
using (SPWeb web = curSite.OpenWeb(SPContext.Current.Web.ID))
{
// Do stuff here
}
}
This will allow you to run elevated code outside a webapplication.
You should also consider using some utility code to wrap such operations in a more functional way. I'm used to use code like this :
public static void RunWithElevatedPrivileges(this SPWeb web, Action<SPSite, SPWeb> codeToRunElevated)
{
if (CheckIfElevated(web))
{
codeToRunElevated(web.Site, web);
}
else
{
using (var elevatedSite = new SPSite(web.Site.ID, web.AllUsers["SHAREPOINT\\system"].UserToken))
{
using (var elevatedWeb = elevatedSite.OpenWeb(web.ID))
{
codeToRunElevated(elevatedSite, elevatedWeb);
}
}
}
}
/// <summary>
/// Indicates whether the context has been elevated
/// </summary>
public static bool CheckIfElevated(SPWeb web)
{
return web.CurrentUser.LoginName == "SHAREPOINT\\system";
}
Using such code, you can simply do, somewhere in your code :
SPContext.Current.Web.RunWithElevatedPrivileges((elevatedSite, elevatedWeb)=>{
// do something will all privileges
});
Both approaches are almost exactly identical. Except in the second approach you are also disposing the SPWeb and SPSite objects of the current context - something you should not do. Does the exception get thrown on a web.Update() call? Is the problem somewhere in the 'do your stuff' code?

Possible to access remote EJBs from a custom LoginModule?

I found some nice hints on how to write a custom realm and loginModule. I'm wondering though if it is possible to access a remote EJB within the custom loginModule.
In my case, I have remote EJBs that provide access to user-entities (via JPA) -- can I use them (e.g. via #EJB annotation)?
Ok, I found the answer myself: works fine! I can get a reference to the remote SLSB via an InitialContext.
Here's the code:
public class UserLoginModule extends AppservPasswordLoginModule {
Logger log = Logger.getLogger(this.getClass().getName());
private UserFacadeLocal userFacade;
public UserLoginModule() {
try {
InitialContext ic = new InitialContext();
userFacade = (UserFacadeLocal) ic.lookup("java:global/MyAppServer/UserFacade!com.skalio.myapp.beans.UserFacadeLocal");
log.info("userFacade bean received");
} catch (NamingException ex) {
log.warning("Unable to get userFacade Bean!");
}
}
#Override
protected void authenticateUser() throws LoginException {
log.fine("Attempting to authenticate user '"+ _username +"', '"+ _password +"'");
User user;
// get the realm
UserRealm userRealm = (UserRealm) _currentRealm;
try {
user = userFacade.authenticate(_username, _password.trim());
userFacade.detach(user);
} catch (UnauthorizedException e) {
log.warning("Authentication failed: "+ e.getMessage());
throw new LoginException("UserLogin authentication failed!");
} catch (Exception e) {
throw new LoginException("UserLogin failed: "+ e.getMessage());
}
log.fine("Authentication successful for "+ user);
// get the groups the user is a member of
String[] grpList = userRealm.authorize(user);
if (grpList == null) {
throw new LoginException("User is not member of any groups");
}
// Add the logged in user to the subject's principals.
// This works, but unfortunately, I can't reach the user object
// afterwards again.
Set principals = _subject.getPrincipals();
principals.add(new UserPrincipalImpl(user));
this.commitUserAuthentication(grpList);
}
}
The trick is to separate the interfaces for the beans from the WAR. I bundle all interfaces and common entities in a separate OSGi module and deploy it with asadmin --type osgi. As a result, the custom UserLoginModule can classload them.