My application is using LDAP for user loging.
Wildfly config:
<security-domain name="LDAPAuth">
<authentication>
<login-module code="LdapExtended" flag="required">
<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
....
</login-module>
<login-module name="Database-role" code="Database" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
.....
</login-module>
<login-module name="Database-default" code="Database" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
....
</login-module>
</authentication>
</security-domain>
My question is how to search ldap users in app? I want to add possibility to search other users in ldap(for already logged users).
You could connect to WildFly management API and read security domain configuration, but you should not do this.
Don't mix server management configuration and application configuration if you have other way.
Provide the LDAP configuration to application (e.g. context parameters in the deployment descriptor or use a property file) and then do sth. like:
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapUrl);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, password);
final LdapContext ctx = new InitialLdapContext(env, null);
final SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<?> namingEnum = ctx.search("dc=mycompany,dc=example", "(uid=*)", searchControls);
while (namingEnum.hasMore()) {
// TODO
}
namingEnum.close();
ctx.close();
Related
I have a trivial problem about execute endpoint resteasy with a trusted SecurityDomain and a specific RolesAllowed.
After a successfull login with loginmodule approach with a login form , the response of endpoint is an access denied (HTTP Status 403 - Access to the requested resource has been denied)
Now I describe the actual case use:
Environment is Jboss AS7, there is an .ear artifact with following configuration
standalone.xml
<management>
...
<security-realm name="EJBRealm">
<authentication>
<jaas name="CustomRealm"/>
</authentication>
</security-realm>
...
</management>
<subsystem xmlns="urn:jboss:domain:security:1.1">
...
<security-domain name="CustomRealm">
<authentication>
<login-module code="Database" flag="sufficient">
<module-option name="dsJndiName" value="java:jboss/jdbc/PUDS"/>
<module-option name="principalsQuery" value="SELECT 'system' FROM dual WHERE ? = 'system'"/>
<module-option name="rolesQuery" value="SELECT 'authenticated', 'Roles' from dual WHERE ? = 'system'"/>
</login-module>
<login-module code="custom.jaas.AuthenticationProxyLoginModule" flag="sufficient" module="custom.authentication">
<module-option name="authBE_ip_port" value="${install.module.authBE_ip_port}"/>
<module-option name="authBE_ip_address" value="${install.module.authBE_ip_address}"/>
<module-option name="authBE_context_path" value="${install.module.authBE_context_path}"/>
</login-module>
</authentication>
</security-domain>
...
</subsystem>
In this ear there is a web-module artifact .war with a set of endpoint with resteasy approach with following configuration:
web.xml
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login.html</form-error-page>
</form-login-config>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>Secured Content</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>ADMIN</role-name>
</security-role>
This role exist on database autentication realm
jboss-web.xml
<jboss-web version="7.1"
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/schema/jbossas/jboss-web_7_1.xsd">
<security-domain>CustomRealm</security-domain>
</jboss-web>
On jboss-web.xml I setting the customrealm defined on standlalone.xml
The resteasy class is defined as followed:
#Component
#Path(value = "/endpoint")
#SecurityDomain("CustomRealm")
#DeclareRoles({"ADMIN", "DEFAULT"})
public class CustomRest implements ICustomRest
{
...
#Override
#GET
#Path(value = "/testendpoint/{id}")
#Consumes(value = MediaType.APPLICATION_JSON)
#RolesAllowed("ADMIN")
public void testendpoint(#PathParam(value = "id") Long id) throws Exception {
//code to execute
}
...
}
This class is annotated with securitydomain at class scope and on method testendpoint define the annotation #RolesAllowed with ADMIN (as defined on web.xml)
If I call the rest uri
http://localhost:8080/api/services/endpoint/testendpoint/23456
the login form is viewed, I insert correct credentials that received from custom.jaas.AuthenticationProxyLoginModule module correctly. The autentication is ok after a successfull login as aspect it.
After all ok, the endpoint don't execute but the response is Access Denied systematically.
What's my wrong?
Login module is configured correctly on standlone.xml, the login form is viewed correctly, the submit credentials is received correctly from custom loginmodule, the method login grant ok authentication, but in the final the response of endpoint is an access denied!!!! Why? It's very trivial and I have got nothing to resolve this trivial problem!
It's all ok , but access denied! I'm sure there is a few wrong that I don't able to understand!
Thanks in advances for a response!
Ok! I find the wrong!!!
I analyzed the code of custom login module and I realized that the native method of loginmodule getRoleSets define a custom role called "authenticated" and not retrieve the roles from database :| !
I fixed so the role with authenticated removing "ADMIN" and all go ok!
Finally I can execute this rest endpoint with a secure login as I aspect it!
I'm very happy to resolve this trouble! Is not a good idea to fix a role on custom method getRoleSets but this is an application on production from many years and I must integrate a webmodule rest endpoint over them!
Thanks all!!
I have a JAX-RS application on WildFly 10 which shall be secured by a simple Basic Auth.
It works so far, but if the authentication fails, the server responds with
<html>
<head>
<title>Error</title>
</head>
<body>Unauthorized</body>
</html>
which is not my desired response. I would prefer a customized (json) response.
How to do that?
What I did so far:
I configured a new Wildfly security domain in my server configuration with a simple UserRolesLoginModule (which is sufficient in my case):
<security-domain name="MySecurityDomain" cache-type="default">
<authentication>
<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
<module-option name="usersProperties" value="${jboss.server.config.dir}/users.properties"/>
<module-option name="rolesProperties" value="${jboss.server.config.dir}/roles.properties"/>
<module-option name="hashAlgorithm" value="MD5"/>
<module-option name="hashEncoding" value="base64"/>
<module-option name="hashCharset" value="UTF-8"/>
<module-option name="unauthenticatedIdentity" value="UnauthenticatedAccess"/>
</login-module>
</authentication>
</security-domain>
I annotated all services in the app:
#SecurityDomain("MySecurityDomain")
#RolesAllowed({ "RoleFromPropertyFile", "AnotherRoleFromPropertyFile" })
I created a jboss-web.xml with the content
<jboss-web>
<security-domain>MySecurityDomain</security-domain>
</jboss-web>
I have a web.xml where I tried a lot of different things without any success... :-(
Current content:
<security-constraint>
<display-name>Deny all HTTP methods except GET and POST</display-name>
<web-resource-collection>
<web-resource-name>NextTest</web-resource-name>
<url-pattern>/mypattern/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>MySecurityRealm</realm-name>
</login-config>
<security-role>
<description>Access to all application parts</description>
<role-name>all</role-name>
</security-role>
<!-- and some more roles -->
I also implemented a ExceptionMapper<EJBAccessException> to generate my own response. But this mapper is only reached when I remove all content of web.xml.
My guess is that undertow is doing the authorization and handles the response on unauthorized access. If I remove the security configuration in the web.xml, the EJBs are accessed, but without evaluating the BasicAuth header. In this case, all requests are denied.
I possible I would avoid to write a Servlet and use an ExceptionMapper instead.
Any ideas what I missed?
I did a little experiment with some code and, while it's not pretty, you could try something like:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
#Provider
public class AuthBodyResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) throws IOException {
if((responseContext.getStatus() == 401) &&
(responseContext.getEntity() instanceof String))
responseContext.setEntity("no services for you!");
}
}
I tested it a bit and it seems to work. Of course, the challenge is where else is there a 401 with a String response body? I'd have to test more to see if this covers everything.
Here is how I do it:
#POST
#Consumes("application/json")
#Produces("application/json")
public Response create(Entity entity) {
try {
Entity created = service().create(entity);
return Response.created(location(created)).entity(created).build();
} catch (ServiceException e) {
return Response.status(e.getStatus()).entity(e).build();
}
}
Notice the return type, Response. This allows you to customize the response, including setting headers etc. It also means you have to write some more wiring code.
I'm using a custom ServiceException here that already has the status in it and use it to set the response code. Then I pass the exception itself which will be returned as JSON.
Is there anybody to know how to register a custom SSL certificate of X509TrustManager in Jboss 7?
As the requirement of my project, I need to customize the default behavior of SSL certificate on X509TrustManager. I already have a custom certificate by extending X509TrustManager and override the default behavior, but now I do not know to register this custom file that Jboss AS7 can understand my own file instead of default X509TrustManager.
public class MyManager implements com.sun.net.ssl.X509TrustManager {
public boolean isClientTrusted(X509Certificate[] chain) { return true; }
public boolean isHostTrusted(X509Certificate[] chain) { return true; }
...
}
Thanks
If you have a security domain you can change the behavior of the Trust Manager in this way:
<security-domain name="CertificateDomain">
<authentication>
<login-module code="CertificateRoles" flag="required">
<module-option name="securityDomain" value="CertificateDomain"/>
<module-option name="verifier" value="org.jboss.security.auth.certs.AnyCertVerifier"/>
....
</login-module>
</authentication>
<jsse keystore-password="..." keystore-url=".." truststore-password="..." truststore-url="..." truststore-provider="..."/>
</security-domain>
truststore-provider Provider of the truststore. The default JDK provider for the truststore type is used if this attribute is null
Security subsystem configuration
Another way is to add the file standalone.xml the following properties (not tested)
<system-properties>
<property name="javax.net.ssl.trustStoreProvider" value="..."/>
<system-properties>
Got problem with JBoss AS7 / EAP6. In MDB, when I lookup for SSB and call its method, the call is always anonymous, i.e. sessionContext.getCallerPrincipal() returns Principal(anonymous). Always... In AS5 everything was fine.
How can I fix it to make a call with an authenticated user?
My MDB:
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/piQueue"),
#ActivationConfigProperty(propertyName = "dLQMaxResent", propertyValue = "3")
})
#SecurityDomain("mySecurityDomain")
public class PIMessageBean implements MessageListener {
...
**//subject always anonymous...**
Subject subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container");
PIManager pim = lookupPIManager();
pim.getPIs(); **//call is anonymous**
...
}
My queue settings:
<subsystem xmlns="urn:jboss:domain:messaging:1.2">
<hornetq-server>
...
<jms-destinations>
<jms-queue name="piQueue">
<entry name="queue/piQueue"/>
<entry name="java:jboss/exported/jms/queue/piQueue"/>
</jms-queue>
</jms-destinations>
<security-domain>mySecurityDomain</security-domain>
</hornetq-server>
</subsystem>
My Security Domain:
<security-domain name="mySecurityDomain" cache-type="default">
<authentication>
<login-module code="com.qu.vad.CustomUsernamePasswordLoginModule" flag="required">
</login-module>
</authentication>
</security-domain>
Solved the problem by doing JAAS login in MDB
With the following, mutual client cert, SSL (TLS) handshake works for a rest endpoint (yay!) - validated via testing and debugging: javax.net logging & wireshark. But...
1st observation: HTTPServletRequest and JAX-RS annotated SecurityContext has null Principal info
2nd observation: Tampering with the login-config.xml, containing application-policy elements, has no effect
In short, TLS works but the transfer of the cert DN to the HTTPServletRequest object in the request thread does not preventing the application from picking up on the caller's ID. Does anyone have any advice?
On JBoss 6:
deploy/jbossweb.sar/server.xml:
<Connector protocol="HTTP/1.1" debug="10"
SSLEnabled="true"
...
secure="true"
clientAuth="true"
sslProtocol = "TLS"
securityDomain="java:/jaas/mydomain"
SSLImplementation="org.jboss.net.ssl.JBossImplementation" />
deploy/jbossweb.sar/META-INF/jboss-beans.xml:
<depends>jboss.security:service=PBESecurityDomain</depends>
deploy/security-service.xml:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.security.plugins.JaasSecurityDomain"
name="jboss.security:service=PBESecurityDomain">
<constructor> <arg type="java.lang.String" value="mydomain"/>
</constructor>
<attribute name="KeyStoreURL">${jboss.server.home.dir}/mykeystore.jks</attribute>
<attribute name="KeyStorePass">{CLASS}org.jboss.security.plugins.FilePassword:${jboss.server.home.dir}/mykeystorepass.pbe</attribute>
<attribute name="TrustStoreURL">${jboss.server.home.dir}/mytruststore.jks</attribute>
<attribute name="TrustStorePass">password</attribute>
<attribute name="Salt">abunchofrandomchars</attribute>
<attribute name="IterationCount">13</attribute>
<depends>jboss.security:service=JaasSecurityManager</depends>
</mbean>
</server>
deploy/security/security-jboss-beans.xml:
<bean name="XMLLoginConfig" class="org.jboss.security.auth.login.XMLLoginConfig">
<property name="configResource">login-config.xml</property>
</bean>
<bean name="SecurityConfig" class="org.jboss.security.plugins.SecurityConfig">
<property name="mbeanServer"><inject bean="JMXKernel" property="mbeanServer"/></property>
<property name="defaultLoginConfig"><inject bean="XMLLoginConfig"/></property>
</bean>
conf/login-config.xml:
<application-policy name="mydomain">
<authentication>
<login-module code="org.jboss.security.auth.spi.BaseCertLoginModule"
flag = "required">
<module-option name="password-stacking">useFirstPass</module-option>
<module-option name="securityDomain">java:/jaas/mydomain</module-option>
<module-option name="verifier">org.jboss.security.auth.certs.AnyCertVerifier</module-option>
<module-option name="principalClass">org.jboss.security.auth.certs.SubjectDNMapping</module-option>
</login-module>
<login-module code="org.jboss.security.auth.spi.UserRolesLoginModu"
flag = "required">
<module-option name="password-stacking">useFirstPass</module-option>
<module-option name="usersProperties">users.properties</module-option>
<module-option name="rolesProperties">roles.properties</module-option>
</login-module>
</authentication>
</application-policy>
war/WEB-INF/jboss-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC
"-//JBoss//DTD Web Application 2.4//EN"
"http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">
<jboss-web>
<security-domain>java:/jaas/mydomain</security-domain>
<context-root>/myapp</context-root>
</jboss-web>
Add the special ClientLoginModule to login-context.xml to fix the null principal issue.
<login-module code="org.jboss.security.ClientLoginModule" flag="required"></login-module>