Spring security 3 + JCIFS ntlm - spring-security

Can they work together?
Some project sample would be great.
I have a web-app on Spring3. And i need to implement NTLM. Spring stopped NTLM support in 3rd version. Is there any possibilities to implement it?
Looking for a sample project.

They can be used together. Essentially what you want to do is hook into the SPNEGO protocol and detect when you receive an NTLM packet from the client. A good description of the protocol can be found here:
http://www.innovation.ch/personal/ronald/ntlm.html
http://blogs.technet.com/b/tristank/archive/2006/08/02/negotiate-this.aspx
Another great resource for NTLM is this:
http://davenport.sourceforge.net/ntlm.html
But you asked for a sample so here goes. To detect an NTLM packet you need to base64
decode the packet and inspect for a starting string:
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String header = request.getHeader("Authorization");
if ((header != null) && header.startsWith("Negotiate ")) {
if (logger.isDebugEnabled()) {
logger.debug("Received Negotiate Header for request " + request.getRequestURL() + ": " + header);
}
byte[] base64Token = header.substring(10).getBytes("UTF-8");
byte[] decodedToken = Base64.decode(base64Token);
if (isNTLMMessage(decodedToken)) {
authenticationRequest = new NTLMServiceRequestToken(decodedToken);
}
...
}
public static boolean isNTLMMessage(byte[] token) {
for (int i = 0; i < 8; i++) {
if (token[i] != NTLMSSP_SIGNATURE[i]) {
return false;
}
}
return true;
}
public static final byte[] NTLMSSP_SIGNATURE = new byte[]{
(byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M',
(byte) 'S', (byte) 'S', (byte) 'P', (byte) 0
};
You'll need to make an authentication provider that can handle that type of authenticationRequest:
import jcifs.Config;
import jcifs.UniAddress;
import jcifs.ntlmssp.NtlmMessage;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbSession;
import jcifs.util.Base64;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsChecker;
import javax.annotation.PostConstruct;
import java.io.IOException;
/**
* User: gcermak
* Date: 3/15/11
* <p/>
*/
public class ActiveDirectoryNTLMAuthenticationProvider implements AuthenticationProvider, InitializingBean {
protected String defaultDomain;
protected String domainController;
protected UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
public ActiveDirectoryNTLMAuthenticationProvider(){
Config.setProperty( "jcifs.smb.client.soTimeout", "1800000" );
Config.setProperty( "jcifs.netbios.cachePolicy", "1200" );
Config.setProperty( "jcifs.smb.lmCompatibility", "0" );
Config.setProperty( "jcifs.smb.client.useExtendedSecurity", "false" );
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
NTLMServiceRequestToken auth = (NTLMServiceRequestToken) authentication;
byte[] token = auth.getToken();
String name = null;
String password = null;
NtlmMessage message = constructNTLMMessage(token);
if (message instanceof Type1Message) {
Type2Message type2msg = null;
try {
type2msg = new Type2Message(new Type1Message(token), getChallenge(), null);
throw new NtlmType2MessageException(Base64.encode(type2msg.toByteArray()));
} catch (IOException e) {
throw new NtlmAuthenticationFailure(e.getMessage());
}
}
if (message instanceof Type3Message) {
final Type3Message type3msg;
try {
type3msg = new Type3Message(token);
} catch (IOException e) {
throw new NtlmAuthenticationFailure(e.getMessage());
}
final byte[] lmResponse = (type3msg.getLMResponse() != null) ? type3msg.getLMResponse() : new byte[0];
final byte[] ntResponse = (type3msg.getNTResponse() != null) ? type3msg.getNTResponse() : new byte[0];
NtlmPasswordAuthentication ntlmPasswordAuthentication = new NtlmPasswordAuthentication(type3msg.getDomain(), type3msg.getUser(), getChallenge(), lmResponse, ntResponse);
String username = ntlmPasswordAuthentication.getUsername();
String domain = ntlmPasswordAuthentication.getDomain();
String workstation = type3msg.getWorkstation();
name = ntlmPasswordAuthentication.getName();
password = ntlmPasswordAuthentication.getPassword();
}
// do custom logic here to find the user ...
userDetailsChecker.check(user);
return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
}
// The Client will only ever send a Type1 or Type3 message ... try 'em both
protected static NtlmMessage constructNTLMMessage(byte[] token) {
NtlmMessage message = null;
try {
message = new Type1Message(token);
return message;
} catch (IOException e) {
if ("Not an NTLMSSP message.".equals(e.getMessage())) {
return null;
}
}
try {
message = new Type3Message(token);
return message;
} catch (IOException e) {
if ("Not an NTLMSSP message.".equals(e.getMessage())) {
return null;
}
}
return message;
}
protected byte[] getChallenge() {
UniAddress dcAddress = null;
try {
dcAddress = UniAddress.getByName(domainController, true);
return SmbSession.getChallenge(dcAddress);
} catch (IOException e) {
throw new NtlmAuthenticationFailure(e.getMessage());
}
}
#Override
public boolean supports(Class<? extends Object> auth) {
return NTLMServiceRequestToken.class.isAssignableFrom(auth);
}
#Override
public void afterPropertiesSet() throws Exception {
// do nothing
}
public void setSmbClientUsername(String smbClientUsername) {
Config.setProperty("jcifs.smb.client.username", smbClientUsername);
}
public void setSmbClientPassword(String smbClientPassword) {
Config.setProperty("jcifs.smb.client.password", smbClientPassword);
}
public void setDefaultDomain(String defaultDomain) {
this.defaultDomain = defaultDomain;
Config.setProperty("jcifs.smb.client.domain", defaultDomain);
}
/**
* 0: Nothing
* 1: Critical [default]
* 2: Basic info. (Can be logged under load)
* 3: Detailed info. (Highest recommended level for production use)
* 4: Individual smb messages
* 6: Hex dumps
* #param logLevel the desired logging level
*/
public void setDebugLevel(int logLevel) throws Exception {
switch(logLevel) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 6:
Config.setProperty("jcifs.util.loglevel", Integer.toString(logLevel));
break;
default:
throw new Exception("Invalid Log Level specified");
}
}
/**
*
* #param winsList a comma separates list of wins addresses (ex. 10.169.10.77,10.169.10.66)
*/
public void setNetBiosWins(String winsList) {
Config.setProperty("jcifs.netbios.wins", winsList);
}
public void setDomainController(String domainController) {
this.domainController = domainController;
}
}
And finally you need to tie it all together in your spring_security.xml file:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config="true" use-expressions="true" disable-url-rewriting="true">
<form-login login-page="/auth/login"
login-processing-url="/auth/j_security_check"/>
<remember-me services-ref="rememberMeServices"/>
<logout invalidate-session="true" logout-success-url="/auth/logoutMessage" logout-url="/auth/logout"/>
<access-denied-handler error-page="/error/accessDenied"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="myUsernamePasswordUserDetailsService">
<password-encoder ref="passwordEncoder">
<salt-source ref="saltSource"/>
</password-encoder>
</authentication-provider>
<authentication-provider ref="NTLMAuthenticationProvider"/>
</authentication-manager>
</beans:beans>
Lastly you need to know how to tie it all together. The protocol as described in the first set of links shows that there are a couple round trips that you need to make between the client and server. Thus in your filter you need a bit more logic:
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.codec.Base64;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.extensions.kerberos.KerberosServiceRequestToken;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* User: gcermak
* Date: 12/5/11
*/
public class SpnegoAuthenticationProcessingFilter extends GenericFilterBean {
private AuthenticationManager authenticationManager;
private AuthenticationSuccessHandler successHandler;
private AuthenticationFailureHandler failureHandler;
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String header = request.getHeader("Authorization");
if ((header != null) && header.startsWith("Negotiate ")) {
if (logger.isDebugEnabled()) {
logger.debug("Received Negotiate Header for request " + request.getRequestURL() + ": " + header);
}
byte[] base64Token = header.substring(10).getBytes("UTF-8");
byte[] decodedToken = Base64.decode(base64Token);
// older versions of ie will sometimes do this
// logic cribbed from jcifs filter implementation jcifs.http.NtlmHttpFilter
if (request.getMethod().equalsIgnoreCase("POST")) {
if (decodedToken[8] == 1) {
logger.debug("NTLM Authorization header contains type-1 message. Sending fake response just to pass this stage...");
Type1Message type1 = new Type1Message(decodedToken);
// respond with a type 2 message, where the challenge is null since we don't
// care about the server response (type-3 message) since we're already authenticated
// (This is just a by-pass - see method javadoc)
Type2Message type2 = new Type2Message(type1, new byte[8], null);
String msg = jcifs.util.Base64.encode(type2.toByteArray());
response.setHeader("WWW-Authenticate", "Negotiate " + msg);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.flushBuffer();
return;
}
}
Authentication authenticationRequest = null;
if (isNTLMMessage(decodedToken)) {
authenticationRequest = new NTLMServiceRequestToken(decodedToken);
}
Authentication authentication;
try {
authentication = authenticationManager.authenticate(authenticationRequest);
} catch (NtlmBaseException e) {
// this happens during the normal course of action of an NTLM authentication
// a type 2 message is the proper response to a type 1 message from the client
// see: http://www.innovation.ch/personal/ronald/ntlm.html
response.setHeader("WWW-Authenticate", e.getMessage());
response.setHeader("Connection", "Keep-Alive");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.flushBuffer();
return;
} catch (AuthenticationException e) {
// That shouldn't happen, as it is most likely a wrong configuration on the server side
logger.warn("Negotiate Header was invalid: " + header, e);
SecurityContextHolder.clearContext();
if (failureHandler != null) {
failureHandler.onAuthenticationFailure(request, response, e);
} else {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.flushBuffer();
}
return;
}
if (successHandler != null) {
successHandler.onAuthenticationSuccess(request, response, authentication);
}
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setSuccessHandler(AuthenticationSuccessHandler successHandler) {
this.successHandler = successHandler;
}
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
this.failureHandler = failureHandler;
}
#Override
public void afterPropertiesSet() throws ServletException {
super.afterPropertiesSet();
Assert.notNull(this.authenticationManager, "authenticationManager must be specified");
}
}
You'll see that in the exception we use "Negotiate" rather than NTLM:
/**
* User: gcermak
* Date: 12/5/11
*/
public class NtlmType2MessageException extends NtlmBaseException {
private static final long serialVersionUID = 1L;
public NtlmType2MessageException(final String type2Msg) {
super("Negotiate " + type2Msg);
}
}
The spring filter (above) was largely patterned on jcifs.http.NtlmHttpFilter which you can find in the source for jcifs here:
http://jcifs.samba.org/
This isn't a whole, downloadable project as you requested but if there is interest from the community I could add this NTLM code to my github project:
http://git.springsource.org/~grantcermak/spring-security/activedirectory-se-security
Hope this helps!
Grant

Related

How to publish and receive data from Android Studio and have it on Google Cloud IoT Core?

I'm a student doing an Android Things project, which is about connecting Rasperi pi with an Accelerometer sensor to get acceleration data, I finished the coding part in Android Studio and the sensor is working fine, then I tried to connect my project to the cloud by following this tutorial: http://blog.blundellapps.co.uk/tut-google-cloud-iot-core-mqtt-on-android/
I think I have to publish the accelerometer data to the cloud by calling this method below in MainActivity class, I did that but still have an error, see the update I did at end of this question please.
#Override
public void onSensorChanged(SensorEvent event) {
Log.d(TAG, "Accel X " + event.values[0]);
Log.d(TAG, "Accel Y " + event.values[1]);
Log.d(TAG, "Accel Z " + event.values[2]);
}
Also, do I have to do something in the cloud platform to receive the data?, I already set up the communication with my Google IoT Core details as shown in the below code:
communicator = new IotCoreCommunicator.Builder()
.withContext(this)
.withCloudRegion("us-central1")
.withProjectId("my-first-project-198704")
.withRegistryId("vibration")
.withDeviceId("my-device")
.withPrivateKeyRawFileId(R.raw.rsa_private)
.build();
This is what I'm seeing in the cloud:
And this is the acceleration data I have in Android Studio:
My project consists of two modules but here I will attach only the second module because the question is limited to 3000 characters only and the second module is what I need to edit I think.
sample module:
AccelerometerActivity class:
package com.cacaosd.sample;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import com.cacaosd.adxl345.ADXL345SensorDriver;
import com.cacaosd.sample.BoardDefaults;
import java.io.IOException;
public class AccelerometerActivity extends Activity implements SensorEventListener {
private static final String TAG = AccelerometerActivity.class.getSimpleName();
private ADXL345SensorDriver mSensorDriver;
private SensorManager mSensorManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerDynamicSensorCallback(new SensorManager.DynamicSensorCallback() {
#Override
public void onDynamicSensorConnected(Sensor sensor) {
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mSensorManager.registerListener(AccelerometerActivity.this,
sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
});
try {
mSensorDriver = new ADXL345SensorDriver(BoardDefaults.getI2CPort());
mSensorDriver.registerAccelerometerSensor();
} catch (IOException e) {
Log.e(TAG, "Error configuring sensor", e);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "Closing sensor");
if (mSensorDriver != null) {
mSensorManager.unregisterListener(this);
try {
mSensorDriver.close();
} catch (IOException e) {
Log.e(TAG, "Error closing sensor", e);
} catch (Exception e) {
e.printStackTrace();
} finally {
mSensorDriver = null;
}
}
}
#Override
public void onSensorChanged(SensorEvent event) {
Log.d(TAG, "Accel X " + event.values[0]);
Log.d(TAG, "Accel Y " + event.values[1]);
Log.d(TAG, "Accel Z " + event.values[2]);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.i(TAG, "sensor accuracy changed: " + accuracy);
}
}
BoardDefaults class:
package com.cacaosd.sample;
import android.os.Build;
import com.google.android.things.pio.PeripheralManagerService;
import java.util.List;
/**
* Created by cagdas on 20.12.2016.
*/
#SuppressWarnings("WeakerAccess")
public class BoardDefaults {
private static final String DEVICE_EDISON_ARDUINO = "edison_arduino";
private static final String DEVICE_EDISON = "edison";
private static final String DEVICE_RPI3 = "rpi3";
private static final String DEVICE_NXP = "imx6ul";
private static String sBoardVariant = "";
/**
* Return the preferred I2C port for each board.
*/
public static String getI2CPort() {
switch (getBoardVariant()) {
case DEVICE_EDISON_ARDUINO:
return "I2C6";
case DEVICE_EDISON:
return "I2C1";
case DEVICE_RPI3:
return "I2C1";
case DEVICE_NXP:
return "I2C2";
default:
throw new IllegalStateException("Unknown Build.DEVICE " + Build.DEVICE);
}
}
private static String getBoardVariant() {
if (!sBoardVariant.isEmpty()) {
return sBoardVariant;
}
sBoardVariant = Build.DEVICE;
// For the edison check the pin prefix
// to always return Edison Breakout pin name when applicable.
if (sBoardVariant.equals(DEVICE_EDISON)) {
PeripheralManagerService pioService = new PeripheralManagerService();
List<String> gpioList = pioService.getGpioList();
if (gpioList.size() != 0) {
String pin = gpioList.get(0);
if (pin.startsWith("IO")) {
sBoardVariant = DEVICE_EDISON_ARDUINO;
}
}
}
return sBoardVariant;
}
}
IotCoreCommunicator class:
package com.cacaosd.sample1;
import android.content.Context;
import android.util.Log;
import java.util.concurrent.TimeUnit;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
public class IotCoreCommunicator {
private static final String SERVER_URI = "ssl://mqtt.googleapis.com:8883";
public static class Builder {
private Context context;
private String projectId;
private String cloudRegion;
private String registryId;
private String deviceId;
private int privateKeyRawFileId;
public Builder withContext(Context context) {
this.context = context;
return this;
}
public Builder withProjectId(String projectId) {
this.projectId = projectId;
return this;
}
public Builder withCloudRegion(String cloudRegion) {
this.cloudRegion = cloudRegion;
return this;
}
public Builder withRegistryId(String registryId) {
this.registryId = registryId;
return this;
}
public Builder withDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
public Builder withPrivateKeyRawFileId(int privateKeyRawFileId) {
this.privateKeyRawFileId = privateKeyRawFileId;
return this;
}
public IotCoreCommunicator build() {
if (context == null) {
throw new IllegalStateException("context must not be null");
}
if (projectId == null) {
throw new IllegalStateException("projectId must not be null");
}
if (cloudRegion == null) {
throw new IllegalStateException("cloudRegion must not be null");
}
if (registryId == null) {
throw new IllegalStateException("registryId must not be null");
}
if (deviceId == null) {
throw new IllegalStateException("deviceId must not be null");
}
String clientId = "projects/" + projectId + "/locations/" + cloudRegion + "/registries/" + registryId + "/devices/" + deviceId;
if (privateKeyRawFileId == 0) {
throw new IllegalStateException("privateKeyRawFileId must not be 0");
}
MqttAndroidClient client = new MqttAndroidClient(context, SERVER_URI, clientId);
IotCorePasswordGenerator passwordGenerator = new IotCorePasswordGenerator(projectId, context.getResources(), privateKeyRawFileId);
return new IotCoreCommunicator(client, deviceId, passwordGenerator);
}
}
private final MqttAndroidClient client;
private final String deviceId;
private final IotCorePasswordGenerator passwordGenerator;
IotCoreCommunicator(MqttAndroidClient client, String deviceId, IotCorePasswordGenerator passwordGenerator) {
this.client = client;
this.deviceId = deviceId;
this.passwordGenerator = passwordGenerator;
}
public void connect() {
monitorConnection();
clientConnect();
subscribeToConfigChanges();
}
private void monitorConnection() {
client.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable cause) {
Log.e("TUT", "connection lost", cause);
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.d("TUT", "message arrived " + topic + " MSG " + message);
// You need to do something with messages when they arrive
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.d("TUT", "delivery complete " + token);
}
});
}
private void clientConnect() {
try {
MqttConnectOptions connectOptions = new MqttConnectOptions();
// Note that the the Google Cloud IoT Core only supports MQTT 3.1.1, and Paho requires that we explicitly set this.
// If you don't, the server will immediately close its connection to your device.
connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
// With Google Cloud IoT Core, the username field is ignored, however it must be set for the
// Paho client library to send the password field. The password field is used to transmit a JWT to authorize the device.
connectOptions.setUserName("unused-but-necessary");
connectOptions.setPassword(passwordGenerator.createJwtRsaPassword());
IMqttToken iMqttToken = client.connect(connectOptions);
iMqttToken.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d("TUT", "success, connected");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e("TUT", "failure, not connected", exception);
}
});
iMqttToken.waitForCompletion(TimeUnit.SECONDS.toMillis(30));
Log.d("TUT", "IoT Core connection established.");
} catch (MqttException e) {
throw new IllegalStateException(e);
}
}
/**
* Configuration is managed and sent from the IoT Core Platform
*/
private void subscribeToConfigChanges() {
try {
client.subscribe("/devices/" + deviceId + "/config", 1);
} catch (MqttException e) {
throw new IllegalStateException(e);
}
}
public void publishMessage(String subtopic, String message) {
String topic = "/devices/" + deviceId + "/" + subtopic;
String payload = "{msg:\"" + message + "\"}";
MqttMessage mqttMessage = new MqttMessage(payload.getBytes());
mqttMessage.setQos(1);
try {
client.publish(topic, mqttMessage);
Log.d("TUT", "IoT Core message published. To topic: " + topic);
} catch (MqttException e) {
throw new IllegalStateException(e);
}
}
public void disconnect() {
try {
Log.d("TUT", "IoT Core connection disconnected.");
client.disconnect();
} catch (MqttException e) {
throw new IllegalStateException(e);
}
}
}
IotCorePasswordGenerator class:
package com.cacaosd.sample1;
import android.content.res.Resources;
import android.util.Base64;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
class IotCorePasswordGenerator {
private final String projectId;
private final Resources resources;
private final int privateKeyRawFileId;
IotCorePasswordGenerator(String projectId, Resources resources, int privateKeyRawFileId) {
this.projectId = projectId;
this.resources = resources;
this.privateKeyRawFileId = privateKeyRawFileId;
}
char[] createJwtRsaPassword() {
try {
byte[] privateKeyBytes = decodePrivateKey(resources, privateKeyRawFileId);
return createJwtRsaPassword(projectId, privateKeyBytes).toCharArray();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Algorithm not supported. (developer error)", e);
} catch (InvalidKeySpecException e) {
throw new IllegalStateException("Invalid Key spec. (developer error)", e);
} catch (IOException e) {
throw new IllegalStateException("Cannot read private key file.", e);
}
}
private static byte[] decodePrivateKey(Resources resources, int privateKeyRawFileId) throws IOException {
try(InputStream inStream = resources.openRawResource(privateKeyRawFileId)) {
return Base64.decode(inputToString(inStream), Base64.DEFAULT);
}
}
private static String inputToString(InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
private static String createJwtRsaPassword(String projectId, byte[] privateKeyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
return createPassword(projectId, privateKeyBytes, "RSA", SignatureAlgorithm.RS256);
}
private static String createPassword(String projectId, byte[] privateKeyBytes, String algorithmName, SignatureAlgorithm signatureAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException {
Instant now = Instant.now();
// Create a JWT to authenticate this device. The device will be disconnected after the token
// expires, and will have to reconnect with a new token. The audience field should always be set
// to the GCP project id.
JwtBuilder jwtBuilder =
Jwts.builder()
.setIssuedAt(Date.from(now))
.setExpiration(Date.from(now.plus(Duration.ofMinutes(20))))
.setAudience(projectId);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory kf = KeyFactory.getInstance(algorithmName);
return jwtBuilder.signWith(signatureAlgorithm, kf.generatePrivate(spec)).compact();
}
}
MainActivity class:
package com.cacaosd.sample1;
import android.app.Activity;
import android.hardware.SensorEvent;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import com.cacaosd.sample.AccelerometerActivity;
import com.cacaosd.sample.R;
import com.cacaosd.sample1.IotCoreCommunicator;
import com.google.android.things.pio.Gpio;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class MainActivity extends Activity {
AccelerometerActivity mAccelerometerActivity = new AccelerometerActivity();
private IotCoreCommunicator communicator;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the communication with your Google IoT Core details
communicator = new IotCoreCommunicator.Builder()
.withContext(this)
.withCloudRegion("us-central1") // ex: europe-west1
.withProjectId("my-first-project-198704") // ex: supercoolproject23236
.withRegistryId("vibration") // ex: my-devices
.withDeviceId("my-device") // ex: my-test-raspberry-pi
.withPrivateKeyRawFileId(R.raw.rsa_private)
.build();
HandlerThread thread = new HandlerThread("MyBackgroundThread");
thread.start();
handler = new Handler(thread.getLooper());
handler.post(connectOffTheMainThread); // Use whatever threading mechanism you want
}
private final Runnable connectOffTheMainThread = new Runnable() {
#Override
public void run() {
communicator.connect();
handler.post(sendMqttMessage);
}
};
private final Runnable sendMqttMessage = new Runnable() {
private int i;
/**
* We post 100 messages as an example, 1 a second
*/
#Override
public void run() {
if (i == 100) {
return;
}
SensorEvent event = null;
// events is the default topic for MQTT communication
String subtopic = "events";
// Your message you want to send
String message = "Hello World " + i++;
communicator.publishMessage(subtopic, message);
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(1));
}
};
#Override
protected void onDestroy() {
communicator.disconnect();
super.onDestroy();
}
MainActivity class:
package com.cacaosd.sample1;
import android.app.Activity;
import android.hardware.SensorEvent;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import com.cacaosd.sample.AccelerometerActivity;
import com.cacaosd.sample.R;
import com.cacaosd.sample1.IotCoreCommunicator;
import com.google.android.things.pio.Gpio;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class MainActivity extends Activity {
AccelerometerActivity mAccelerometerActivity = new AccelerometerActivity();
private IotCoreCommunicator communicator;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the communication with your Google IoT Core details
communicator = new IotCoreCommunicator.Builder()
.withContext(this)
.withCloudRegion("us-central1") // ex: europe-west1
.withProjectId("my-first-project-198704") // ex: supercoolproject23236
.withRegistryId("vibration") // ex: my-devices
.withDeviceId("my-device") // ex: my-test-raspberry-pi
.withPrivateKeyRawFileId(R.raw.rsa_private)
.build();
HandlerThread thread = new HandlerThread("MyBackgroundThread");
thread.start();
handler = new Handler(thread.getLooper());
handler.post(connectOffTheMainThread); // Use whatever threading mechanism you want
}
private final Runnable connectOffTheMainThread = new Runnable() {
#Override
public void run() {
communicator.connect();
handler.post(sendMqttMessage);
}
};
private final Runnable sendMqttMessage = new Runnable() {
private int i;
/**
* We post 100 messages as an example, 1 a second
*/
#Override
public void run() {
if (i == 100) {
return;
}
SensorEvent event = null;
// events is the default topic for MQTT communication
String subtopic = "events";
// Your message you want to send
String message = "Hello World " + i++;
communicator.publishMessage(subtopic, message);
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(1));
}
};
#Override
protected void onDestroy() {
communicator.disconnect();
super.onDestroy();
}
}
Update:
I added a third input (int acceleration) on publishMessage() method inside IotCoreCommunicator class like below:
public void publishMessage(String subtopic, String message, int acceleration) {
String topic = "/devices/" + deviceId + "/" + subtopic;
String payload = "{msg:\"" + message + "\"}";
MqttMessage mqttMessage = new MqttMessage(payload.getBytes());
mqttMessage.setQos(1);
try {
client.publish(topic, mqttMessage);
Log.d("TUT", "IoT Core message published. To topic: " + topic);
} catch (MqttException e) {
throw new IllegalStateException(e);
}
}
Then I call it on run() method inside the MainActivity class like below:
public void run() {
if (i == 100) {
return;
}
SensorEvent event = null;
// events is the default topic for MQTT communication
String subtopic = "events";
// Your message you want to send
String message = "Hello World " + i++;
int acceleration = mAccelerometerActivity.onSensorChanged(SensorEvent event.values);
communicator.publishMessage(subtopic, message, acceleration);
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(1));
}
};
But I still have this error in the below screenshot:
(';' or ) expected)
Also the third input I added is shown like never been used as you see in the screenshot below, is this has any effect?
Thank you.

receive raw binary message without using Message class or MessageCracker class in quickfix/j

After sending a logon message using quickfix/J I want to receive the raw incoming message and do my own thing with the message as far as decoding it goes. Using Single Binary Encoding (SBE)
https://github.com/real-logic/simple-binary-encoding
For example:
I send logon message 8=FIX.4.4^9=95^35=A^34=1^49=FROMComp^52=20151009-18:22:35.968^56=HistReplay^98=0^108=30^141=Y^553=ABC^554=ABC^10=238^ in the FIX format as per the target hosts instructions
http://www.cmegroup.com/confluence/display/EPICSANDBOX/MDP+3.0+-+TCP+Replay+Messages
Then the target computer sends back a heartbeat message in SBE format. The message from the target computer sends the message back in SBE format and using Quickfix/J message and messagecracker the raw data is not recognized or I just simply do not know a way to receive the raw data using fromApp
I want to intercept the raw data coming in so that i can send it to my own SBE decoder instead of using quickfix/J message and messagecracker. Anybody know how?
Application class
package tcpconnectiontest;
import java.util.logging.Level;
import java.util.logging.Logger;
import quickfix.Application;
import quickfix.DoNotSend;
import quickfix.FieldNotFound;
import quickfix.IncorrectDataFormat;
import quickfix.IncorrectTagValue;
import quickfix.Message;
import quickfix.MessageCracker;
import quickfix.RejectLogon;
import quickfix.SessionID;
import quickfix.UnsupportedMessageType;
import quickfix.field.MsgType;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Administrator
*/
public class TestApplicationImpl extends MessageCracker implements Application {
#Override
public void fromAdmin(Message arg0, SessionID arg1) throws FieldNotFound,
IncorrectDataFormat, IncorrectTagValue, RejectLogon {
System.out.println("Successfully called fromAdmin for sessionId : "
+ arg0);
}
#Override
public void fromApp(Message arg0, SessionID arg1) throws FieldNotFound,
IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
System.out.println("Successfully called fromApp for sessionId : "
+ arg0);
crack(arg0, arg1);
System.out.println(arg0);
}
#Override
public void onCreate(SessionID arg0) {
System.out.println("Successfully called onCreate for sessionId : "
+ arg0);
}
#Override
public void onLogon(SessionID arg0) {
System.out.println("Successfully logged on for sessionId : " + arg0);
}
#Override
public void onLogout(SessionID arg0) {
System.out.println("Successfully logged out for sessionId : " + arg0);
}
#Override
public void toAdmin(Message message, SessionID sessionId) {
try {
System.out.println("Inside toAdmin");
final String msgType = message.getHeader().getString(MsgType.FIELD);
if(MsgType.LOGON.compareTo(msgType) == 0)
{
message.setString(quickfix.field.Username.FIELD, "MGE");
message.setString(quickfix.field.Password.FIELD, "MGE");
}
} catch (FieldNotFound ex) {
Logger.getLogger(TestApplicationImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void toApp(Message arg0, SessionID arg1) throws DoNotSend {
System.out.println("Message : " + arg0 + " for sessionid : " + arg1);
}
#Override
public void onMessage(Message message, SessionID sessionID)
throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue {
System.out.println("Inside Logon Message");
super.onMessage(message, sessionID);
System.out.println(message.toString());
}
}
main class
package tcpconnectiontest;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import quickfix.Application;
import quickfix.ConfigError;
import quickfix.DefaultMessageFactory;
import quickfix.FileLogFactory;
import quickfix.FileStoreFactory;
import quickfix.MessageFactory;
import quickfix.Session;
import quickfix.SessionID;
import quickfix.SessionNotFound;
import quickfix.SessionSettings;
import quickfix.SocketInitiator;
/**
*
* #author Administrator
*/
public class TCPConnectionTest {
private static WriteFIXMLMessage fixml = new WriteFIXMLMessage();
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
SocketInitiator socketInitiator = null;
try {
SessionSettings sessionSettings = new SessionSettings("C:\\ProgramData\\MDR\\sessionSettings.txt");
Application application = new TestApplicationImpl();
FileStoreFactory fileStoreFactory = new FileStoreFactory(sessionSettings);
FileLogFactory logFactory = new FileLogFactory(sessionSettings);
MessageFactory messageFactory = new DefaultMessageFactory();
socketInitiator = new SocketInitiator(application,
fileStoreFactory, sessionSettings, logFactory,
messageFactory);
socketInitiator.start();
//Thread.sleep(5000);
SessionID sessionId = socketInitiator.getSessions().get(0);
//sendLogonRequest(sessionId);
Thread.sleep(5000);
socketInitiator.getManagedSessions();
int i = 0;
do {
try {
if(socketInitiator.isLoggedOn())
{
sendMDRRequest(sessionId);
}
else
{
System.out.println(socketInitiator.isLoggedOn());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
} while ((!socketInitiator.isLoggedOn()) && (i < 30));
} catch (ConfigError e) {
e.printStackTrace();
} catch (SessionNotFound e) {
e.printStackTrace();
} catch (Exception exp) {
exp.printStackTrace();
} finally {
if (socketInitiator != null) {
socketInitiator.stop(true);
}
}
}
private static void sendLogonRequest(SessionID sessionId)
throws SessionNotFound {
boolean sent = Session.sendToTarget(fixml.loginXML(), sessionId);
System.out.println("Logon Message Sent : " + sent);
}
private static void sendMDRRequest(SessionID sessionId)
throws SessionNotFound {
boolean sentnext = Session.sendToTarget(fixml.requestXML(), sessionId);
System.out.println("MDR Message Sent : " + sentnext);
}
}

Error 500 use POST Request with jquery

i use jquery to achive ajax request to one servlet.
Now when use a GET request like this:
$("#nbtnLogin").click(function(){
login=$("#nloginIn").val();
passwd=$("#npasswdIn").val();
//alert(login + " " + passwd);
$.get(
"http://localhost:8080/EsLab2-Servlet-AsyncServerandClient/EsLab2Servlet",
{login:login, passwd:passwd, type:"i"},
function(data,stato){
alert("dati: " + data + "\n stato: " + stato);
$("#ajaxResponse1").empty().append(data +"\n");
},"text"
);
everything works and I get response but when I change $.get in $.post
$("#nbtnLogin").click(function(){
login=$("#nloginIn").val();
passwd=$("#npasswdIn").val();
//alert(login + " " + passwd);
$.post(
"http://localhost:8080/EsLab2-Servlet-AsyncServerandClient/EsLab2Servlet",
{login:login, passwd:passwd, type:"i"},
function(data,stato){
alert("dati: " + data + "\n stato: " + stato);
$("#ajaxResponse1").empty().append(data +"\n");
},"text"
);
Initially remains pending and after a few seconds I get error code 500 why?
package MyServlet;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet(name="EsLab2Servlet",asyncSupported = true)
public class EsLab2Servlet extends HttpServlet {
Map<String, String> hashmap;
public EsLab2Servlet() {
hashmap=new HashMap<String, String>();
}
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code>
* methods.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// response.setContentType("text/html;charset=UTF-8");
//PrintWriter out = response.getWriter();
final AsyncContext context = request.startAsync();
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
final ServletInputStream input = request.getInputStream();
final ServletOutputStream output = response.getOutputStream();
System.out.println("ciao");
input.setReadListener(new ReadListenerImpl(input, output, context, hashmap));
// context.complete();
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* #return a String containing servlet description
*/
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
and
package MyServlet;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.AsyncContext;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.swing.JOptionPane;
class ReadListenerImpl implements ReadListener {
private ServletInputStream input;
private ServletOutputStream output;
private AsyncContext context;
private Map<String, String> hashmap;
ReadListenerImpl(ServletInputStream input, ServletOutputStream output, AsyncContext context , Map hashmap) {
this.input = input;
this.output = output;
this.context = context;
this.hashmap = hashmap;
}
//metodi
protected synchronized String processLogin(HttpServletRequest request)throws ServletException, IOException{
String user = null;
String passwd= null;
String cont=null;
user=request.getParameter("login").toString();
passwd=request.getParameter("passwd").toString();
//cont = "Hello" + user + passwd;
if(passwd.equals("")){
cont="inserire password!";
}
else {
if((hashmap.containsKey(user))){
if((hashmap.get(user).compareTo(passwd))==0)
cont="login: OK";
else cont="login: Abort";
}
else cont="login: Abort";
/*hashmap.put(user,passwd);
cont=cont + "elemento inserito";
*/
}
return cont;
}
protected synchronized String processInsert(HttpServletRequest request)throws ServletException, IOException{
String user = null;
String passwd= null;
String cont=null;
user=request.getParameter("login").toString();
passwd=request.getParameter("passwd").toString();
//cont = "Hello" + user + passwd;
if(passwd.equals("") || user.equals("")){
cont="malformed request";
}
else {
if((hashmap.containsKey(user))){
cont="utente già presente";
}
else {
hashmap.put(user, passwd);
cont="insert: Ok";
}
}
return cont;
}
protected synchronized String processView(HttpServletRequest request)throws ServletException, IOException{
String cont = null;
String user = null;
user=request.getParameter("login").toString();
if((hashmap.containsKey(user))){
cont=hashmap.get(user);
}
else cont="utente non presente!";
return cont;
}
#Override
public void onDataAvailable() throws IOException {
System.out.println("onDataAvailable");
}
#Override
public void onAllDataRead() throws IOException {
System.out.println("ricevuti tutti i dati!...lancio il thread...");
context.start(new Runnable() {
String cont = null;
#Override
public void run() {
try {
System.out.println("Sono il thread adesso lavoro e poi ritorno disponibile...");
HttpServletRequest req = (HttpServletRequest) context.getRequest();
if (req.getParameter("type").compareTo("l") == 0 ) cont=processLogin(req);
else if (req.getParameter("type").compareTo("i") == 0) cont= processInsert(req);
else if (req.getParameter("type").compareTo("s") == 0) cont= processView(req);
output.println(cont);
output.flush();
} catch (ServletException ex) {
Logger.getLogger(ReadListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ReadListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
} finally{
try {
input.close();
output.close();
context.complete();
} catch (IOException ex) {
Logger.getLogger(ReadListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
}
#Override
public void onError(Throwable t) {
System.out.println("c'è un errore");
}
}
If you don't read all data, the callback onAllDataRead is not called.
Below, an example:
final ServletInputStream input = request.getInputStream();
input.setReadListener(new ReadListener() {
#Override
public void onDataAvailable() throws IOException {
byte b[]=new byte[1024];
while(input.isReady()&&input.read(b)!=-1){
}
}
#Override
public void onAllDataRead() throws IOException {
context.getResponse().getWriter().write("ciao");
context.complete();
}
#Override
public void onError(Throwable t) {
context.complete();
}
});

Issue with accessing FacesContext in Servlet Filter

I am trying to access FacesContext in Servlet Filter,
And sometimes (not everytime) i encounter internal server errors.
AuthenticationFilter.java
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
public class AuthenticationFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
UserDetailsBean userBean = null;
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
FacesContext context = FacesUtil.getFacesContext(req, res);
String param = req.getParameter("PARAMETER_VALUES");
if((param!=null && param.isEmpty()) || !isAuthenticated(req)) {
if(param != null && !param.isEmpty()) {
userBean = new UserDetailsBean();
setCookies(param, userBean, req, res);
FacesUtil.setManagedBeanInView(context, "userDetailsBean", userBean);
request.setAttribute("userDetailsBean", userBean);
chain.doFilter(request, response);
}
else {
String homePage = "http://homePage";
res.sendRedirect(homePage);
}
}
else {
try {
if(!context.isPostback()){
userBean = getUserBeanFromCookies(req.getCookies());
request.setAttribute("userDetailsBean", userBean);
}
} catch(Exception e) {
userBean = getUserBeanFromCookies(req.getCookies());
request.setAttribute("userDetailsBean", userBean);
}
chain.doFilter(request, response);
}
}
private UserDetailsBean getUserBeanFromCookies(Cookie[] cookies) {
UserDetailsBean userBean = new UserDetailsBean();
for(Cookie c: cookies) {
String cName = c.getName();
if("userId".equals(cName)) {
userBean.setUserNbr(c.getValue());
}
else if("userEmail".equals(cName)) {
userBean.setEmail(c.getValue());
}
else if("firstName".equals(cName)) {
userBean.setFirstName(c.getValue());
}
else if("lastName".equals(cName)) {
userBean.setLastName(c.getValue());
}
}
return userBean;
}
private boolean setCookies(String param, UserDetailsBean userBean, HttpServletRequest request, HttpServletResponse response) {
boolean validUser = false;
if(param != null) {
String strParams = new String(Base64.decodeBase64(param.getBytes()));
String[] pairs = strParams.split("&");
for(String pp: pairs) {
String[] s = pp.split("=");
if("p_userid".equals(s[0])) {
userBean.setUserNbr(s[1]);
validUser = true;
}
else if("p_email".equals(s[0])){
userBean.setEmail(s[1]);
}
else if("p_first_name".equals(s[0])) {
userBean.setFirstName(s[1]);
}
else if("p_last_name".equals(s[0])) {
userBean.setLastName(s[1]);
}
}
}
if(validUser) {
String cookiePath = "/";
Cookie cookie = new Cookie("userId", userBean.getUserNbr());
cookie.setMaxAge(-1); // Expire time. -1 = by end of current session, 0 = immediately expire it, otherwise just the lifetime in seconds.
cookie.setPath(cookiePath);
response.addCookie(cookie);
cookie = new Cookie("userEmail", userBean.getEmail());
cookie.setMaxAge(-1);
cookie.setPath(cookiePath);
response.addCookie(cookie);
cookie = new Cookie("firstName",userBean.getFirstName());
cookie.setMaxAge(-1);
cookie.setPath(cookiePath);
response.addCookie(cookie);
cookie = new Cookie("lastName", userBean.getLastName());
cookie.setMaxAge(-1);
cookie.setPath(cookiePath);
response.addCookie(cookie);
}
return validUser;
}
public boolean isAuthenticated(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if(cookies == null) {
return false;
}
for(Cookie c: cookies) {
String cName = c.getName();
if("userId".equals(cName)) {
if(c.getValue() == null || c.getValue().isEmpty()) {
return false;
}
else {
return true;
}
}
}
return false;
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
UserDetailsBean.java
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ViewScoped
#ManagedBean(name="userDetailsBean")
public class UserDetailsBean implements Serializable {
private String userNbr;
private String email;
private String firstName;
private String lastName;
public String getUserNbr() {
return userNbr;
}
public void setUserNbr(String userNbr) {
this.userNbr = userNbr;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
FacesUtil.java
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FacesUtil {
public static FacesContext getFacesContext(HttpServletRequest request, HttpServletResponse response) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null) {
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
facesContext = contextFactory.getFacesContext(request.getSession().getServletContext(), request, response, lifecycle);
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "");
facesContext.setViewRoot(view);
FacesContextWrapper.setCurrentInstance(facesContext);
}
return facesContext;
}
// Wrap the protected FacesContext.setCurrentInstance() in a inner class.
private static abstract class FacesContextWrapper extends FacesContext {
protected static void setCurrentInstance(FacesContext facesContext) {
FacesContext.setCurrentInstance(facesContext);
}
}
}
Here the authentication is actually handling by other application,
Once the user login it will send a request parameter (PARAMETER_VALUES) with some information.
We are using JSF 2.1.9 & Tomcat 6.0.35.
i am getting an error at this line from Filter
FacesContext context = FacesUtil.getFacesContext(req, res);
Error stack trace:
Exception=java.lang.NullPointerException
at org.apache.catalina.connector.Request.parseParameters(Request.java:2599)
at org.apache.catalina.connector.Request.getParameter(Request.java:1106)
at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:355)
at javax.servlet.ServletRequestWrapper.getParameter(ServletRequestWrapper.java:158)
at com.sun.faces.context.RequestParameterMap.containsKey(RequestParameterMap.java:99)
at java.util.Collections$UnmodifiableMap.containsKey(Collections.java:1280)
at com.sun.faces.renderkit.ResponseStateManagerImpl.isPostback(ResponseStateManagerImpl.java:84)
at com.sun.faces.context.FacesContextImpl.isPostback(FacesContextImpl.java:207)
at com.sandbox.external.site.test.filter.AuthenticationFilter.doFilter(AuthenticationFilter.java:36)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.ha.tcp.ReplicationValve.invoke(ReplicationValve.java:347)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:396)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
When i see the source code of Tomcat 6.0.35 at the line stated in error,
if (!getMethod().equalsIgnoreCase("POST"))
return;
cannot find much information here.
You cannot access the FacesContext in a filter because the FacesContext is initialized by the FacesServlet, and your filter is processed before the request arrives to the servlet.
If it works sometimes, it is probably because of a side effect (JSF creates one FacesContext for every request, every request is bound to a Thread and Threads are reused by the servlet container).
I'm also wondering why are you trying to reinvent the wheel by implementing you own security filters. There is already existing solution which are available (like Spring Security or standard JEE security) and well tested.
See this question for more information from BalusC:
How do I retrieve the FacesContext within a Filter

Struts2 ActionContext and Response for chaining actions

I have a pretty complex problem about struts2 chaining actions, thanks in advance for your patience reading my problem. I will try my best to describe it clearly.
Below is my struts.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.enable.SlashesInActionNames" value="true" />
<constant name="struts.devMode" value="false" />
<package name="default" extends="struts-default" namespace="/">
<action name="test" class="com.bv.test.TestAction1" >
<result name="success" type="chain">y</result>
</action>
<action name="x">
<result name="success">/index.jsp</result>
</action>
<action name="y" class="com.bv.test.TestAction2">
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
My logic is like this:
When accessing to /myapp/test, TestAction1 will handle the request;
In TestAction1, I "include" action x (my 2nd action in my config) like this:
ResponseImpl myResponse = new ResponseImpl(response);
RequestDispatcher rd = request.getRequestDispatcher("/x.action");
rd.include(request, myResponse);
And the important thing is I am using a customized ResponseIml when including "x.action".
After including, I return "success", so the result chains to action y (3rd action in my config);
And at last, TestAction2 continue to handle the request, it will go to success result, and the jsp should be rendered, but what I see is a blank page.
The jsp file is very simple:
index.jsp
<h1>Test!</h1>
My question/puzzle is:
In TestAction1, if I get the response from ServletActionContext, I
am getting different ones before and after including; before
including is the default response, but after including I got an
instance of my customized ResponseImpl; I expect to get the same
one: i.e.: the default response;
In TestAction2, I get response from ServletActionContext, what I got
is the instance of my customized ResponseIml. This is my most important thing, I think I should get a default response instance here, i.e.: org.apache.catalina.connector.Response, I am running on JBoss;
I am getting a different ActionContext in TestAction2 (compared with
the ActionContext I get in TestAction1).
This problem really drive me on the nuts, I have spent days on it.
Any advice will be appreciated!
Thanks a million!!
My Code:
TestAction1:
public class TestAction1 {
public String execute() {
ActionContext ac = ActionContext.getContext();
System.out.println("Before including: the action context is : " + ac);
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
System.out.println("Before including: the response is : " + response);
ResponseImpl myResponse = new ResponseImpl(response);
RequestDispatcher rd = request.getRequestDispatcher("/x.action");
try {
rd.include(request, myResponse);
String s = myResponse.getOutput();
System.out.println("get from response: " + s);
}
catch (Exception e) {
e.printStackTrace();
}
ac = ActionContext.getContext();
System.out.println("After including : the action context is : " + ac);
response = ServletActionContext.getResponse();
System.out.println("After including : the response is : " + response);
return "success";
}
}
ResponseImpl:
import java.util.Locale;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.Cookie;
import javax.servlet.jsp.JspWriter;
/**
*
*
*/
public class ResponseImpl extends HttpServletResponseWrapper {
//=========================================================
// Private fields.
//=========================================================
private ServletOutputStream outputStream = null;
private ByteArrayOutputStream byteArrayOutputStream = null;
private StringWriter stringWriter = null;
private PrintWriter printWriter = null;
private HttpServletResponse _response = null;
private String contentType= "text/html";
private String encoding = "UTF-8";
/**
*
*/
class ServletOutputStream extends javax.servlet.ServletOutputStream {
private OutputStream outputStream = null;
/**
*
*/
ServletOutputStream(ByteArrayOutputStream outputStream) {
super();
this.outputStream = outputStream;
}
/**
*
*/
public void write(int b) throws IOException {
this.outputStream.write(b);
}
}
//=========================================================
// Public constructors and methods.
//=========================================================
/**
*
*/
public ResponseImpl(HttpServletResponse response) {
super(response);
this._response = response;
}
/**
*
*/
public String getOutput() {
if (this.stringWriter != null) {
return this.stringWriter.toString();
}
if (this.byteArrayOutputStream != null) {
try {
return this.byteArrayOutputStream.toString(this.encoding);
}
catch (UnsupportedEncodingException e) {
}
return this.byteArrayOutputStream.toString();
}
return null;
}
//=========================================================
// Implements HttpServletResponse interface.
//=========================================================
public void addCookie(Cookie cookie) {
}
public void addDateHeader(String name, long date) {
}
public void addHeader(String name, String value) {
}
public void addIntHeader(String name, int value) {
}
public boolean containsHeader(String name) {
return false;
}
public String encodeRedirectURL(String url) {
if (null != this._response) {
url = this._response.encodeRedirectURL(url);
}
return url;
}
public String encodeURL(String url) {
if (null != this._response) {
url = this._response.encodeURL(url);
}
return url;
}
public void sendError(int sc) {
}
public void sendError(int sc, String msg) {
}
public void sendRedirect(String location) {
}
public void setDateHeader(String name, long date) {
}
public void setHeader(String name, String value) {
}
public void setIntHeader(String name, int value) {
}
public void setStatus(int sc) {
}
public void resetBuffer() {
}
//=========================================================
// Implements deprecated HttpServletResponse methods.
//=========================================================
public void setStatus(int sc, String sm) {
}
//=========================================================
// Implements deprecated HttpServletResponse methods.
//=========================================================
public String encodeRedirectUrl(String url) {
return encodeRedirectURL(url);
}
public String encodeUrl(String url) {
return encodeURL(url);
}
//=========================================================
// Implements ServletResponse interface.
//=========================================================
public void flushBuffer() {
}
public int getBufferSize() {
return 0;
}
public String getCharacterEncoding() {
return this.encoding;
}
public String getContentType() {
return this.contentType;
}
public Locale getLocale() {
return null;
}
public javax.servlet.ServletOutputStream getOutputStream() {
if (this.outputStream == null) {
this.byteArrayOutputStream = new ByteArrayOutputStream();
this.outputStream =
new ServletOutputStream(this.byteArrayOutputStream);
}
return this.outputStream;
}
public PrintWriter getWriter() {
if (this.printWriter == null) {
this.stringWriter = new StringWriter();
this.printWriter = new PrintWriter(this.stringWriter);
}
return this.printWriter;
}
public boolean isCommitted() {
return true;
}
public void reset() {
}
public void setBufferSize(int size) {
}
public void setCharacterEncoding(String charset) {
}
public void setContentLength(int len) {
}
public void setContentType(String type) {
int needle = type.indexOf(";");
if (-1 == needle) {
this.contentType = type;
}
else {
this.contentType = type.substring(0, needle);
String pattern = "charset=";
int index = type.indexOf(pattern, needle);
if (-1 != index) {
this.encoding = type.substring(index + pattern.length());
}
}
}
public void setLocale(Locale locale) {
}
}
TestAction2:
public class TestAction2 {
public String execute() {
ActionContext ac = ActionContext.getContext();
System.out.println("In TestAction 2 : the action context is : " + ac);
HttpServletResponse response = ServletActionContext.getResponse();
System.out.println("In TestAction 2 : the response is : " + response);
return "success";
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts2 Application</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
</web-app>
This is my debug info.
Before including: the action context is
:com.opensymphony.xwork2.ActionContext#c639ce
Before including: the response is :
org.apache.catalina.connector.ResponseFacade#8b677f
get from response: <h1>Test!</h1>
After including : the action context is :
com.opensymphony.xwork2.ActionContext#2445d7
After including : the response is : com.bv.test.ResponseImpl#165547d
In TestAction 2 : the action context is
:com.opensymphony.xwork2.ActionContext#19478c7
In TestAction 2 : the response is : com.bv.test.ResponseImpl#165547d
So, I have different ActionContext instances before and after the including!!
When you do rd.include another request is fired internally inside the web server. So from struts point of view it sees a completely new request and a new action context is created as a result. (that's why you need to include 'INCLUDE' thing on the struts2 filter.. so that it's seeing included requests as well). Probably since thread local variables are used to track action context and all that when you do ActionContext.getContext() the context related to the new request (related to the include) gets retrieved.
Did you try resetting the response to the initial one in a finally block like below
try {
rd.include(request, myResponse);
String s = myResponse.getOutput();
System.out.println("get from response: " + s);
}
catch (Exception e) {
e.printStackTrace();
} finally {
ServletActionContext.setResponse(response);
}
If this resolves the response issue.. you could probably store the string 's' as a variable in the action context and retrieve it inside your Action2
You could also try the following as well. Instead of using chaining.. inside your TestAction1 include the TestAction2 with the original response. return 'none' from the action as the return value.
public class TestAction1 {
public String execute() {
ActionContext ac = ActionContext.getContext();
System.out.println("Before including: the action context is : " + ac);
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
System.out.println("Before including: the response is : " + response);
ResponseImpl myResponse = new ResponseImpl(response);
RequestDispatcher rd = request.getRequestDispatcher("/x.action");
try {
rd.include(request, myResponse);
String s = myResponse.getOutput();
System.out.println("get from response: " + s);
}
catch (Exception e) {
e.printStackTrace();
}
RequestDispatcher rd = request.getRequestDispatcher("/y.action");
try {
rd.include(request, response);
}
catch (Exception e) {
e.printStackTrace();
} finally {
return "none";
}
}
}

Resources