JSESSIONIDSSO cookie is not getting written upon login - single-sign-on

I have a number of applications currently running on Wildfly 10 and using the Picketbox security system with SSO. I am currently upgrading to Wildfly 17 and have converted the security configuration to use the Elytron subsystem, but am having issues getting the SSO cookie to write. I am not upgrading to the JEE8 security APIs.
One of the apps ("app1") being migrated is quite simple, using stock standard form posts via a login-config section in web.xml. This app works correctly: I get the login form, submit my credentials, and the response includes the JSESSIONIDSSO cookie. A second app ("app2") is implemented a bit differently. It also uses login-config but the login page submits to a custom servlet which logs in programmatically using HttpServletRequest.login(username, password). When I submit my credentials in this app they are authenticated correctly but no JSESSIONIDSSO cookie is written.
Wildfly Config
(it's originally set up for AD, but is temporarily set to read users from a file for simpler testing)
<subsystem ...>
...
<application-security-domains>
<application-security-domain name="active-directory" http-authentication-factory="ad-http-auth">
<single-sign-on domain="localhost" key-store="sso-ad-keystore" key-alias="localhost">
<credential-reference clear-text="ssopass"/>
</single-sign-on>
</application-security-domain>
</application-security-domains>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:7.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<security-domains>
...
<security-domain name="LocalFileDomain" default-realm="LocalFileRealm" permission-mapper="default-permission-mapper">
<realm name="LocalFileRealm"/>
</security-domain>
</security-domains>
<security-realms>
...
<filesystem-realm name="LocalFileRealm">
<file path="fs-realm-users" relative-to="jboss.server.config.dir"/>
</filesystem-realm>
</security-realms>
<http>
...
<http-authentication-factory name="ad-http-auth" security-domain="LocalFileDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="FORM">
<mechanism-realm realm-name="active-directory"/>
</mechanism>
<mechanism mechanism-name="BASIC">
<mechanism-realm realm-name="active-directory"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
</subsystem>
App1
<login-config>
<auth-method>BASIC?silent=true,FORM</auth-method>
<realm-name>App Realm</realm-name>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/noAccess.html</form-error-page>
</form-login-config>
</login-config>
<form action="j_security_check" method="post">
Username: <input name="j_username" type="text"/>
Password: <input name="j_password" type="password"/>
<input type="submit"/>
</form>
App2
<login-config>
<auth-method>BASIC?silent=true,FORM</auth-method>
<realm-name>App Realm</realm-name>
<form-login-config>
<form-login-page>/login</form-login-page>
<form-error-page>/login</form-error-page>
</form-login-config>
</login-config>
Login form uses Angular to post to the login servlet, which looks like this:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
if (req.getUserPrincipal() == null) {
String username = req.getParameter(USERNAME_FIELD);
String password = req.getParameter(PASSWORD_FIELD);
if (username == null || password == null) {
setResponseStatusAndOutput(LoginResultStatus.UNAUTHORISED, resp);
return;
}
try {
Person person = this.personRepository.findByLogin(username);
if (person != null) {
req.login(username, password);
req.authenticate(resp); // I've tried with and without this line
setResponseStatusAndOutput(LoginResultStatus.SUCCESS, resp);
} else {
setResponseStatusAndOutput(LoginResultStatus.UNAUTHORISED, resp);
}
} catch (ServletException ex) {
setResponseStatusAndOutput(LoginResultStatus.UNAUTHORISED, resp);
}
} else {
setResponseStatusAndOutput(LoginResultStatus.SUCCESS, resp);
}
}
private void setResponseStatusAndOutput(LoginResultStatus loginResultStatus, HttpServletResponse response) throws IOException {
response.setContentType("application/json");
response.setStatus(loginResultStatus.getCode());
response.getOutputStream().print(String.format("{ \"status\": \"%s\" }", loginResultStatus.getValue()));
}
Does Undertow not apply the SSO stuff to requests that are authenticated this way, maybe because I've missed the spot in the filter chain where it's set? Or is there something else I'm not doing right?
Edit 1: I've done some more testing to try and narrow down the issue.
Wildfly 17 Elytron, posting to j_security_check: Logs in OK, writes the JSESSIONIDSSO cookie.
Wildfly 17 Elytron, posting to custom login servlet: Logs in OK, does not write the JSESSIONIDSSO cookie.
Wildfly 10 Legacy, posting to j_security_check: Logs in OK, writes the JSESSIONIDSSO cookie.
Wildfly 10 Legacy, posting to custom login servlet: Logs in OK, writes the JSESSIONIDSSO cookie.
I've created a test project to demonstrate this, which includes the config files for Wildfly 10 and 17.

Related

Shiro error redirection

How can I make Shiro redirect errors in a Web app?
I have configured my web.xml
<error-page>
<error-code>500</error-code>
<location...</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>...</location>
</error-page>
And it works fine. But when Shiro is active and I raise a 500 error on purpose the page stays blank.
I think I got it... It was blank because the method onAccessDenied() was returning false wherever a problem happened.
To fix it, one possible solution is this:
#Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
throws Exception {
if(!executeLogin(request, response)){
//throw exception
} else {
return true;
}
}
Of course make sure your error pages defined in web.xml are anon in your shiro.ini
e.g.
[urls]
/error500.xhtml = anon

Spring Security-flow after authentication entry point

I am trying to secure my REST services using spring security.My problem is ,I have stuck at authentication entry point.even though I have configured a UsernamePasswordAuthenticationFilter,execution flow could not reach there.
Below is the XML configuration
<sec:http create-session="stateless" auto-config="false"
authentication-manager-ref="authenticationManager"
entry-point-ref="http403EntryPoint"
>
<sec:form-login
login-processing-url="/login"
password-parameter="password"
username-parameter="username"
/>
<!-- <sec:custom-filter ref="tokenCreatorAndValidator" position="FORM_LOGIN_FILTER" /> -->
<sec:intercept-url pattern="/**"
method="POST"
access="ROLE_USER"
/>
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider user-service-ref="authenticatorDAO">
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="http403EntryPoint"
class="com.app.login.RestAuthenticationEntryPoint" />
code for AuthenticationEntryPoint is given below.
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{
#Override
public void commence( HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException ) throws IOException{
System.out.println("in RestAuthenticationEntrypoint\n--------------------------------------\n");
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
}
}
can anybody tell me what I m doing wrong here?
Sorry cannot post comments hence posting this as answer.
Check if ExceptionTranslationFilter is getting called in your exiting configuration.
OR
Did you injected http403EntryPoint in ExceptionTranslationFilter?
<bean id="etf" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="http403EntryPoint"/>
</bean
>

ActiveMQ producer XA transaction

I am trying to configure my custom ActiveMQ producer to use XA transaction. Unfortunately it does't work as expected because messages are sent to queue immediately instead of waiting for transactions to commit.
Here is the producer:
public class MyProducer {
#Autowired
#Qualifier("myTemplate")
private JmsTemplate template;
#Transactional
public void sendMessage(final Order order) {
template.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
ObjectMessage message = new ActiveMQObjectMessage();
message.setObject(order);
return message;
}
});
}
}
And this is template and connection factory configuration:
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/activemq/ConnectionFactory" />
</bean>
<bean id="myTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="jmsConnectionFactory"
p:defaultDestination-ref="myDestination"
p:sessionTransacted="true"
p:sessionAcknowledgeModeName="SESSION_TRANSACTED" />
As you can see I am using ConnectionFactory initiated via JNDI. It is configured on JBoss EAP 6.3:
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.1">
<resource-adapters>
<resource-adapter id="activemq-rar.rar">
<module slot="main" id="org.apache.activemq.ra"/>
<transaction-support>XATransaction</transaction-support>
<config-property name="ServerUrl">
tcp://localhost:61616
</config-property>
<connection-definitions>
<connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/activemq/ConnectionFactory" enabled="true" use-java-context="true" pool-name="ActiveMQConnectionFactoryPool" use-ccm="true">
<xa-pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>20</max-pool-size>
</xa-pool>
</connection-definition>
</connection-definitions>
</resource-adapter>
</resource-adapters>
</subsystem>
When I debug I can see that JmsTemplate is configured properly:
it has a reference to valid connection factory org.apache.activemq.ra.ActiveMQConnectionFactory
connection factory has a reference to valid transaction manager: org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl
session transacted is set to true
session acknowledge mode is set to SESSION_TRANSACTED(0)
Do you have any idea why these messages are pushed to the queue immediately and they are not removed when transaction is rolled back (e.g. when I throw exception at the end of "sendMessage" method?
You need to show the rest of your configuration (transaction manager etc).
It looks like you don't have transactions enabled in the application context so the template is committing the transaction itself.
Do you have <tx:annotation-driven/> in the context?

How to connect JBoss 7.1.1 remoting -jmx via java code?

I have a JBoss 7.1.1 server, for which I want to write jmx client. As far I understood, jboss 7.1.1 is not using typical rmi based jmx and they have given a layer of remoting-jmx over native management. I am using following code:
JMXServiceURL address = new JMXServiceURL("service:jmx:remoting-jmx://localhost:9999");
Map env = JMXConnectorConfig.getEnvironment(paramtbl);
JMXConnector connector = JMXConnectorFactory.connect(address, env);
But it is giving following exception:
java.net.MalformedURLException: Unsupported protocol: remoting-jmx
I googled it and the following thread seems relevant:
https://community.jboss.org/thread/204653?tstart=0
It asks to add jboss's libraries to my classpath. I tried that also but still getting same exception.
I got the same exception when trying to get a JmxServiceUrl.
Make sure that in your standalone.xml you have the following:
<subsystem xmlns="urn:jboss:domain:jmx:1.1">
<show-model value="true"/>
<remoting-connector use-management-endpoint="true" />
</subsystem>
And you should include in project classpath the jar named: jboss-client.jar, it can be found in JBOSS_DIRECTORY/bin/client. In fact, the JMX client must include that jar in its classpath.
This tip fixed the problem for me..Hope it will be helpful for you
Tried to do the same from Arquillian test on JBoss AS7 and finally had to use:
import org.jboss.remotingjmx.RemotingConnectorProvider;
RemotingConnectorProvider s = new RemotingConnectorProvider();
JMXConnector connector = s.newJMXConnector(url, credentials);
connector.connect();
Could not have "module name="org.jboss.remoting-jmx" services="import"" working
Also works with
environment.put("jmx.remote.protocol.provider.pkgs", "org.jboss.remotingjmx");
JMXConnector connector = JMXConnectorFactory.connect(url, environment);
connector.connect();
I used this code to connect to JBoss in a remote server
ModelControllerClient client = null;
try {
client = createClient(InetAddress.getByName("172.16.73.12"), 9999,
"admin", "pass", "ManagementRealm");
}
catch (UnknownHostException e) {
e.printStackTrace();
}
Where createClient is a method I wrote -
private ModelControllerClient createClient(final InetAddress host,
final int port, final String username, final String password,
final String securityRealmName) {
final CallbackHandler callbackHandler = new CallbackHandler() {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback current : callbacks) {
if (current instanceof NameCallback) {
NameCallback ncb = (NameCallback) current;
ncb.setName(username);
} else if (current instanceof PasswordCallback) {
PasswordCallback pcb = (PasswordCallback) current;
pcb.setPassword(password.toCharArray());
} else if (current instanceof RealmCallback) {
RealmCallback rcb = (RealmCallback) current;
rcb.setText(rcb.getDefaultText());
} else {
throw new UnsupportedCallbackException(current);
}
}
}
};
return ModelControllerClient.Factory
.create(host, port, callbackHandler);
}
For more information on how to read the data obtained from Server or for the complete project using Java/Google visualizer API (to show the statistics in Graph after every 10 secs) , Please refer to this tutorial -
http://javacodingtutorial.blogspot.com/2014/05/reading-jboss-memory-usage-using-java.html
Add the following to your jboss-deployment-structure
<dependencies>
<module name="org.jboss.remoting3.remoting-jmx" services="import"/>
</dependencies>
Activate JMX remoting subsystem by adding following entry in standalone.xml
<subsystem xmlns="urn:jboss:domain:ee:1.1">
<!-- Activate JMX remoting -->
<global-modules>
<module name="org.jboss.remoting-jmx" slot="main"/>
</global-modules>
...
</subsystem>
It seems like "jboss-client.jar" is not available at run-time for JMX connection, So make sure that you have added "jboss-client.jar" in the class path.
And also you are using deprecated protocol "remoting-jmx" instead of "remote".
i.e, "service:jmx:remote://localhost:9999"
Hope it helps.

Spring Security Web App: different login, same authentication object

i use spring security to organize the security and user management in my GWT application. If i login as "admin", logout, and login as another user the "SecurityContextHolder.getContext()" still returns me the "admin" authentication though i use the standard spring security logout URL (/j_spring_security_logout) and after logout have to login again to access the page... somebody has a hint? I'm at the end of my knowledge =/
filters in my web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
applicationcontext.xml:
<bean class="service.security.DefaultPermissionEvaluator" id="permissionEvaluator"/>
<bean class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" id="expressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator"/>
</bean>
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>
<bean class="service.security.DefaultAuthenticationProvider" id="authenticationProvider"/>
<bean class="service.security.DefaultUserDetailsManager" id="userDetailsManager"/>
<bean class="service.security.DefaultAuthenticationListener" id="customAuthListener"/>
<sec:authentication-manager>
<sec:authentication-provider ref="authenticationProvider">
</sec:authentication-provider>
</sec:authentication-manager>
<sec:http auto-config="true" use-expressions="true">
<sec:form-login default-target-url="/Index.html" always-use-default-target="true"/>
<sec:logout invalidate-session="true" logout-success-url="/" logout-url="/j_spring_security_logout"/>
<sec:intercept-url pattern="/service/admin/**" access="hasRole('ADMIN')"/>
<sec:intercept-url pattern="/**" access="hasRole('USER')"/>
</sec:http>
The problem was i did this:
class ServiceExample extends HttpServlet {
private final Authentication auth;
public ServiceExample() {
this.auth = SecurityContextHolder.getContext().getAuthentication()
}
public User getCurrentUser() {
return (User) this.auth.getPrincipal();
}
}
instead of:
class ServiceExample extends HttpServlet {
public ServiceExample() {
}
public User getCurrentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
Which makes the SecurityContext initialize once when somebody logs in (Jetty behavior) and not changing when somebody else logs in cause of jetty using the same instance...