Https authentication in android L using bouncy castle - https

So since the apache libraries have been deprecated in Android L, I have been trying to implement the ssl authentication with a web sphere server using the UrlConnection api. The code is as follows:
The function calling the web service
SSLContext ctx = SSLContext.getInstance("TLS");
try
{
ctx.init(null, new TrustManager[] { new UDMX509TrustManager(
Constants.UDM_SERVER_SOURCE) }, new SecureRandom());
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url
.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /*
* milliseconds
*/);
urlConnection.setSSLSocketFactory(ctx.getSocketFactory());
if (jsonObject != null)
{
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type",
"application/json");
DataOutputStream printout = new DataOutputStream(
urlConnection.getOutputStream());
printout.writeBytes(URLEncoder.encode(jsonObject.toString(),
"UTF-8"));
printout.flush();
printout.close();
InputStream in = urlConnection.getInputStream();
Reader reader = null;
reader = new InputStreamReader(in, "UTF-8");
char[] buffer = new char[1000];
reader.read(buffer);
response = new String(buffer);
MLog.v("response is", response);
}/*
* catch (Exception e) { e.printStackTrace(); } }
*/else
{
return response = Constants.NETWORK_UNAVAILABLE;
}
/*
* } catch (Exception e) { e.printStackTrace(); }
*/
And my custom X509 manager is :
public class UDMX509TrustManager implements X509TrustManager
{
/*
* The default X509TrustManager returned by IbmX509. We'll delegate
* decisions to it, and fall back to the logic in this class if the default
* X509TrustManager doesn't trust it.
*/
X509TrustManager pkixTrustManager;
public UDMX509TrustManager(int source) throws Exception
{
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("BKS");
InputStream in = null;
int resId = 0;
if (source == Constants.UDM_SERVER_SOURCE)
{
resId = Constants.SERVER_KEYSTORE_PATH;
} else if (source == Constants.MQTT_SERVER_SOURCE)
{
resId = Constants.MQTT_KEYSTORE_PATH;
}
in = VerizonUdmApplication.getContext().getResources()
.openRawResource(resId);
ks.load(in, Constants.KEYSTORE_PASSWORD.toCharArray());
in.close();
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager tms[] = tmf.getTrustManagers();
/*
* Iterate over the returned trustmanagers, look for an instance of
* X509TrustManager. If found, use that as our "default" trust manager.
*/
for (int i = 0; i < tms.length; i++)
{
if (tms[i] instanceof X509TrustManager)
{
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn't initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
try
{
pkixTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep)
{
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
try
{
pkixTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep)
{
/*
* Possibly pop up a dialog box asking whether to trust the cert
* chain.
*/
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers()
{
return pkixTrustManager.getAcceptedIssuers();
}
}
Now so far I've created two scenarios:
Generating bks with the machine ip as the common name parameter:- The
exception I get in that case is : java.io.ioexception: hostname
"xx.xx.xx.xx" was not verified android
Generating bks with the domain name as the common name parameter:-
The exception I encountered in this case is :
java.net.UnknownHostException: Unable to resolve host "host name": No
address associated with hostname
Also Note- for testing purpose I'm using a tomcat server. Any ideas how I can resolve this and complete authentication with the server with this api?
Any help on the same would be greatly appreciated.

Related

IBM MQ JMSWMQ0018: Failed to connect to queue manager 'MY_LOCAL_QM' with connection mode 'Client' and host name 'MY_LOCAL_QM(1401)'

I created a queue manager, queue, channel(Server-connection).
When I try to send a message, see this error:
com.ibm.msg.client.jms.DetailedIllegalStateException: JMSWMQ0018: Failed to connect to queue manager 'MY_LOCAL_QM' with connection mode 'Client' and host name 'epspa(1401)'.
Check the queue manager is started and if running in client mode, check there is a listener running. Please see the linked exception for more information.
Maybe I need to set a user to queue manager? Because I use the same java code, but try to connect to another queue manager, and it works fine. But it doesn't work with my queue manager.
IBM MQ installed on another PC.
private static final String HOST = "epspa";
private static final int PORT = 1401;
private static final String CHANNEL = "API.SVRCONN_LOCAL";
private static final String QMN = "MY_LOCAL_QM";
private static final String QUEUE_NAME = "API.QUEUE_NAME";
private static final String message ="message";
public static String sendMessage(String message) {
String result = "Error";
try {
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
cf.setHostName(HOST);
cf.setChannel(CHANNEL);
cf.setPort(PORT);
cf.setQueueManager(QMN);
cf.setTransportType(WMQConstants.WMQ_MESSAGE_BODY_MQ);
Destination destination = null;
MessageProducer producer = null;
Connection c = cf.createConnection();
Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = s.createQueue(QUEUE_NAME);
producer = s.createProducer(destination);
TextMessage tmo = s.createTextMessage();
((MQDestination) destination).setMessageBodyStyle
(WMQConstants.WMQ_MESSAGE_BODY_MQ);
tmo.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 1208);
tmo.setIntProperty(WMQConstants.JMS_IBM_ENCODING,546);
tmo.setText(message);
producer.send(tmo);
result = "Success!";
} catch (JMSException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
cf.setTransportType(WMQConstants.WMQ_MESSAGE_BODY_MQ);
Well, that's not correct. It should be:
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
JMSWMQ0018: Failed to connect to queue manager
A JMS error does not give enough details about what MQ is complaining about. You need to output the LinkedException.
catch (JMSException e)
{
if (e != null)
{
System.err.println("getLinkedException()=" + e.getLinkedException());
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
}
}
Are you sure that port # of 1401 is correct? The default port # for MQ is 1414. Start runmqsc against your queue manager. i.e.
runmqsc MY_LOCAL_QM
then issue the following command:
DIS LISTENER(LISTENER.TCP)
what value is given for the PORT attribute?
tmo.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 1208);
tmo.setIntProperty(WMQConstants.JMS_IBM_ENCODING,546);
Why are you setting the CCSID and Encoding? Why don't you let JMS & MQ take care of it?
Here is a fully functioning JMS program that puts a message to a queue:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import javax.jms.*;
import com.ibm.mq.jms.*;
import com.ibm.msg.client.wmq.WMQConstants;
/**
* Program Name
* MQTestJMS11
*
* Description
* This java JMS class will connect to a remote queue manager and put a message to a queue.
*
* Sample Command Line Parameters
* -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -q TEST.Q1 -u UserID -x Password
*
* #author Roger Lacroix
*/
public class MQTestJMS11
{
private static final SimpleDateFormat LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
private Hashtable<String,String> params;
private MQQueueConnectionFactory mqQCF = null;
/**
* The constructor
*/
public MQTestJMS11()
{
super();
params = new Hashtable<String,String>();
}
/**
* Make sure the required parameters are present.
* #return true/false
*/
private boolean allParamsPresent()
{
boolean b = params.containsKey("-h") && params.containsKey("-p") &&
params.containsKey("-c") && params.containsKey("-m") &&
params.containsKey("-q") &&
params.containsKey("-u") && params.containsKey("-x");
if (b)
{
try
{
Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
b = false;
}
}
return b;
}
/**
* Extract the command-line parameters and initialize the MQ variables.
* #param args
* #throws IllegalArgumentException
*/
private void init(String[] args) throws IllegalArgumentException
{
if (args.length > 0 && (args.length % 2) == 0)
{
for (int i = 0; i < args.length; i += 2)
{
params.put(args[i], args[i + 1]);
}
}
else
{
throw new IllegalArgumentException();
}
if (allParamsPresent())
{
try
{
mqQCF = new MQQueueConnectionFactory();
mqQCF.setQueueManager((String) params.get("-m"));
mqQCF.setHostName((String) params.get("-h"));
mqQCF.setChannel((String) params.get("-c"));
mqQCF.setTransportType(WMQConstants.WMQ_CM_CLIENT);
try
{
mqQCF.setPort(Integer.parseInt((String) params.get("-p")));
}
catch (NumberFormatException e)
{
mqQCF.setPort(1414);
}
}
catch (JMSException e)
{
if (e != null)
{
MQTestJMS11.logger("getLinkedException()=" + e.getLinkedException());
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
}
throw new IllegalArgumentException();
}
catch (Exception e)
{
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
throw new IllegalArgumentException();
}
}
else
{
throw new IllegalArgumentException();
}
}
/**
* Test the connection to the queue manager.
* #throws MQException
*/
private void testConn()
{
QueueConnection conn = null;
QueueSession session = null;
Queue myQ = null;
try
{
conn = mqQCF.createQueueConnection((String) params.get("-u"), (String) params.get("-x"));
conn.start();
session = conn.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
MQTestJMS11.logger("successfully connected.");
myQ = session.createQueue((String) params.get("-q"));
MQDestination mqd = (MQDestination) myQ;
mqd.setTargetClient(WMQConstants.WMQ_CLIENT_JMS_COMPLIANT);
// mqd.setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ);
sendMsg( session, myQ);
}
catch (JMSException e)
{
if (e != null)
{
MQTestJMS11.logger("getLinkedException()=" + e.getLinkedException());
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
}
}
catch (Exception e)
{
MQTestJMS11.logger(e.getLocalizedMessage());
e.printStackTrace();
}
finally
{
try
{
if (session != null)
session.close();
}
catch (Exception ex)
{
MQTestJMS11.logger("session.close() : " + ex.getLocalizedMessage());
}
try
{
if (conn != null)
conn.stop();
}
catch (Exception ex)
{
MQTestJMS11.logger("connection.stop() : " + ex.getLocalizedMessage());
}
try
{
if (conn != null)
conn.close();
}
catch (Exception ex)
{
MQTestJMS11.logger("connection.close() : " + ex.getLocalizedMessage());
}
}
}
/**
* Send a message to a queue.
* #throws MQException
*/
private void sendMsg(QueueSession session, Queue myQ) throws JMSException
{
QueueSender sender = null;
try
{
TextMessage msg = session.createTextMessage();
msg.setText("Nice simple test. Time in 'ms' is -> " + System.currentTimeMillis());
// msg.setJMSReplyTo(tq);
// msg.setJMSDeliveryMode( DeliveryMode.NON_PERSISTENT);
MQTestJMS11.logger("Sending request to " + myQ.getQueueName());
MQTestJMS11.logger("");
sender = session.createSender(myQ);
sender.send(msg);
}
finally
{
try
{
if (sender != null)
sender.close();
}
catch (Exception ex)
{
MQTestJMS11.logger("sender.close() : " + ex.getLocalizedMessage());
}
}
}
/**
* A simple logger method
* #param data
*/
public static void logger(String data)
{
String className = Thread.currentThread().getStackTrace()[2].getClassName();
// Remove the package info.
if ( (className != null) && (className.lastIndexOf('.') != -1) )
className = className.substring(className.lastIndexOf('.')+1);
System.out.println(LOGGER_TIMESTAMP.format(new Date())+" "+className+": "+Thread.currentThread().getStackTrace()[2].getMethodName()+": "+data);
}
/**
* mainline
* #param args
*/
public static void main(String[] args)
{
MQTestJMS11 write = new MQTestJMS11();
try
{
write.init(args);
write.testConn();
}
catch (IllegalArgumentException e)
{
MQTestJMS11.logger("Usage: java MQTestJMS11 -m QueueManagerName -h host -p port -c channel -q JMS_Queue_Name -u UserID -x Password");
System.exit(1);
}
catch (Exception e)
{
MQTestJMS11.logger(e.getLocalizedMessage());
System.exit(1);
}
System.exit(0);
}
}

JMS-Loadtest using Gatling: unable to initialize ContextFactory of IBM MQ

I'm implementing a load test scenario against a IBM MQ with Gatling.
The setup is basically the same as mentioned here
Problem: I'm not able to initialize the required ContextFactory with IBM MQ - which should be com.ibm.mq.jms.context.WMQInitialContextFactory.
The WMQInitialContextFactory cannot be found.
But my build.sbt is containing the IBM MQ dependency correctly (being successfully retrieved by our internal Nexus :
"com.ibm.mq" % "com.ibm.mq" % "8.0.0.3"
My gatling scenario:
package com.myawesomecompany.loadtest
import com.ibm.mq._
import com.ibm.mq.jms.MQConnectionFactory
import com.ibm.mq.jms.JMSMQ_Messages
import com.ibm.msg.client.wmq.common.CommonConstants
import io.gatling.core.Predef._
import io.gatling.core.scenario.Simulation
import io.gatling.jms.Predef._
import javax.jms._
import scala.concurrent.duration._
class JMSLoadTest extends Simulation {
val jmsConfiguration = jms
.connectionFactoryName("ConnectionFactory")
.url("devmq01.company.dmz")
.credentials("mqm", "mqm")
.contextFactory(classOf[com.ibm.mq.jms.context.WMQInitialContrextFactory].getName)
.listenerCount(1)
.usePersistentDeliveryMode
val scn = scenario("Load testing GPRSForwarder").repeat(1) {
exec(jms("testing GPRSForwarder...").reqreply
.queue("COMPANY.TEST.QUEUE")
.textMessage("00001404020611100E033102C20EBB51CC1C036EFFFF00010002323802000200FE05001400000000FFFFFFFFFFFFFFFFFF040010038B0D6912EB10CE070206110F37298C")
.jmsType("test_jms_type")
)
}
setUp(scn.inject(rampUsersPerSec(10) to 1000 during (2 minutes)))
.protocols(jmsConfiguration)
}
The setup is equivalent to this one - but instead of using ActiveMQInitalContextFactory, I'm forced to use the "counterpart" of IBM MQ.
According to official docks the WMQInitialContextFactory should be in com.ibm.mq.jms.context but it is not. Ore is there some constant in CommonConstants which I can use to initialize a ContextFactory ?
Thanks a lot in advance.
Problem: I'm not able to initialize the required ContextFactory with
IBM MQ - which should be
com.ibm.mq.jms.context.WMQInitialContextFactory. The
WMQInitialContextFactory cannot be found.
Do not use WMQInitialContextFactory. It was an MQ SupportPac someone created where they wanted to use MQ as the JNDI repository. It is not a good idea plus the SupportPac does not support any form of security (i.e. SSL/TLS or security exit).
You should use a file based MQ JNDI. Here's a basic example:
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.ibm.mq.MQException;
/**
* Program Name
* TestJMS01
*
* Description
* This java JMS class will connect to a remote queue manager
* using JNDI and put a message to a queue.
*
* Sample Command Line Parameters
* -x myQCF -q dev.test.q -f C:\JNDI-Directory\roger\mqjndi
*
* Sample MQ JNDI Commands:
* DEFINE QCF(myQCF) QMANAGER(MQA1) CHANNEL(TEST.CHL) HOSTNAME(127.0.0.1) PORT(1415) TRANSPORT(CLIENT) FAILIFQUIESCE(YES)
* DEFINE Q(dev.test.q) QUEUE(TEST1) QMANAGER(MQA1) TARGCLIENT(JMS) FAILIFQUIESCE(YES)
*
* #author Roger Lacroix, Capitalware Inc.
*/
public class TestJMS01
{
private static final String JNDI_CONTEXT = "com.sun.jndi.fscontext.RefFSContextFactory";
private QueueConnectionFactory cf;
private Queue q;
private Hashtable<String,String> params = null;
private String userID = "tester";
private String password = "mypwd";
public TestJMS01() throws NamingException
{
super();
}
/**
* Make sure the required parameters are present.
* #return true/false
*/
private boolean allParamsPresent()
{
return (params.containsKey("-x") && params.containsKey("-q") && params.containsKey("-f"));
}
/**
* Extract the command-line parameters and initialize the MQ variables.
* #param args
* #throws IllegalArgumentException
*/
private void init(String[] args) throws IllegalArgumentException
{
params = new Hashtable<String,String>(10);
if (args.length > 0 && (args.length % 2) == 0)
{
for (int i = 0; i < args.length; i += 2)
{
params.put(args[i], args[i + 1]);
}
}
else
{
throw new IllegalArgumentException();
}
if (allParamsPresent())
{
Hashtable<String,Object> env = new Hashtable<String,Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_CONTEXT);
env.put(Context.PROVIDER_URL, "file:/"+(String) params.get("-f"));
try
{
Context ctx = new InitialContext(env);
cf = (QueueConnectionFactory) ctx.lookup((String) params.get("-x"));
q = (Queue) ctx.lookup((String) params.get("-q"));
}
catch (NamingException e)
{
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
throw new IllegalArgumentException();
}
}
else
{
throw new IllegalArgumentException();
}
}
/**
* Test the connection to the queue manager.
* #throws MQException
*/
private void testConn() throws JMSException
{
QueueConnection connection = null;
QueueSession session = null;
try
{
connection = cf.createQueueConnection(userID, password);
connection.start();
session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
sendMsg(session);
}
catch (JMSException e)
{
System.err.println("getLinkedException()=" + e.getLinkedException());
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
}
finally
{
try
{
session.close();
}
catch (Exception ex)
{
System.err.println("session.close() : " + ex.getLocalizedMessage());
}
try
{
connection.stop();
}
catch (Exception ex)
{
System.err.println("connection.stop() : " + ex.getLocalizedMessage());
}
try
{
connection.close();
}
catch (Exception ex)
{
System.err.println("connection.close() : " + ex.getLocalizedMessage());
}
}
}
/**
* Send a message to a queue.
* #throws MQException
*/
private void sendMsg(QueueSession session) throws JMSException
{
QueueSender sender = null;
try
{
TextMessage msg = session.createTextMessage();
msg.setText("Nice simple test. Time in 'ms' is -> " + System.currentTimeMillis());
// msg.setJMSReplyTo(tq);
// msg.setJMSDeliveryMode( DeliveryMode.NON_PERSISTENT);
System.out.println("Sending request to " + q.getQueueName());
System.out.println();
sender = session.createSender(q);
sender.send(msg);
}
catch (JMSException e)
{
System.err.println("getLinkedException()=" + e.getLinkedException());
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
}
finally
{
try
{
sender.close();
}
catch (Exception ex)
{
System.err.println("sender.close() : " + ex.getLocalizedMessage());
}
}
}
/**
* main line
* #param args
*/
public static void main(String[] args)
{
try
{
TestJMS01 tj = new TestJMS01();
tj.init(args);
tj.testConn();
}
catch (IllegalArgumentException e)
{
System.err.println("Usage: java TestJMS01 -x QueueConnectionFactoryName -q JMS_Queue_Name -f path_to_MQ_JNDI");
System.exit(1);
}
catch (NamingException ex)
{
System.err.println(ex.getLocalizedMessage());
ex.printStackTrace();
}
catch (JMSException e)
{
System.err.println("getLinkedException()=" + e.getLinkedException());
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
}
catch (Exception ex)
{
System.err.println(ex.getLocalizedMessage());
ex.printStackTrace();
}
}
}
Not directly related to your problem, but JMSToolBox with its scripting feature, is a tool that allows to perform bulk/load test on IBM MQ.
With it you can define a script, composed of steps, that will read a template with variable placeholders and repeatedly put messages in one or multiple destinations. It can also directly read saved messages from a directory etc.
You can download it from SourceForge here
Documentation of the script feature is here

Access YouTube brand account using GoogleSignInApi

I am following this guide: https://developers.google.com/identity/sign-in/android/
Which prompts me for my Google user and I login ok, I can access the youtube data api.
However I want it to prompt me to choose my linked brand account instead. Is this possible? I had it working from a nodejs app but it doesn't seem supported in this case.
Turns out you can't. Just not supported at this time.
Instead you need to go via https://github.com/openid/AppAuth-Android/ using just the youtube scope, this prompts for your channels/brand accounts correctly.
Then to use the result with the youtube api I did this in the AppAuth TokenActivity:
/**
* Define a global instance of the HTTP transport.
*/
public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/**
* Define a global instance of the JSON factory.
*/
public static final JsonFactory JSON_FACTORY = new JacksonFactory();
private YouTube mYoutube;
#MainThread
private void fetchUserInfo(String accessToken, String idToken, AuthorizationException ex) {
if (ex != null) {
Log.e(TAG, "Token refresh failed when fetching user info");
mUserInfoJson.set(null);
runOnUiThread(this::displayAuthorized);
return;
}
mYoutube = new YouTube.Builder(TokenActivity.HTTP_TRANSPORT, TokenActivity.JSON_FACTORY, new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest httpRequest) throws IOException {
httpRequest.getHeaders().setAuthorization("Bearer " + accessToken);
}
})
.build();
mExecutor.submit(() -> {
try {
YouTube.LiveBroadcasts.List list = mYoutube.liveBroadcasts()
.list("id, snippet, contentDetails, status")
.setMine(true);
Log.i(TAG, "List to string " + list.toString());
LiveBroadcastListResponse response = list
.execute();
JSONObject obj = new JSONObject();
obj.put("name", response.getItems().get(0).getSnippet().getTitle());
mUserInfoJson.set(obj);
} catch (IOException e) {
Log.e(TAG, "Failed to construct user info endpoint URL", e);
} catch (JSONException e) {
Log.e(TAG, "Failed to set name", e);
// e.printStackTrace();
}
runOnUiThread(this::displayAuthorized);
});

Web service request working in old version of android (2.3.3) but not in later versions (4.0.3, 4.3)

While working on an application for android that uses web services I encounterd a bad request (response code 400) message when trying to retrieve some data in android versions 4.0.3 and 4.3. The perculiar thing however is that when sending the same request using the same code but on a device using android version 2.3.3 it works without any problems. I have also tried using httpGet instead of HttpsURLConnection, while this work for all versions it does not provide a solution as I need the added security.
My code is as follows:
private String executeRequest(String urlAddress)
{
String responce = null;
String msg = null;
int error = 0;
try {
URL url = new URL(urlAddress);
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
SSLSocketFactory factory = SecureSocketFactory.getSSLSocketFactory();
connection.setSSLSocketFactory(factory);
connection.setHostnameVerifier(new Verifier());
connection.setDoOutput(true);
connection.setDoInput(true);
if (method == RequestMethod.POST)
{
connection.setRequestMethod("POST");
}
msg = connection.getResponseMessage();
error = connection.getResponseCode();
if ("OK".equals(msg))
{
InputStream content = (InputStream) connection.getContent();
responce = convertStreamToString(content);
}
else
{
responce = "Error " + error;
}
connection.disconnect();
} catch (Exception e) {
responce = e.toString();
}
return responce;
}
And the code of SecureSocketFactory.getSSLSocketFactory():
public static SSLSocketFactory getSSLSocketFactory()
throws IOException
{
if(ssf_ == null)
{
javax.net.ssl.KeyManager kms[] = null;
javax.net.ssl.TrustManager tms[] = null;
SSLContext context = null;
try
{
tms = CustomTrustManager.getTrustManagers();
context = SSLContext.getInstance("TLS");
context.init(kms, tms, null);
}
catch(GeneralSecurityException e)
{
IOException io = new IOException(e.getLocalizedMessage());
io.setStackTrace(e.getStackTrace());
throw io;
}
ssf_ = context.getSocketFactory();
}
return ssf_;
}
and the code of CustomTrustManager.getTrustManagers()
static TrustManager[] getTrustManagers(String trustStoreFile, String trustStorePW)
throws NoSuchAlgorithmException, KeyStoreException
{
String alg = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmFact = TrustManagerFactory.getInstance(alg);
tmFact.init((KeyStore)null);
TrustManager tms[] = tmFact.getTrustManagers();
for(int i = 0; i < tms.length; i++)
if(tms[i] instanceof X509TrustManager)
tms[i] = new CustomTrustManager((X509TrustManager)tms[i]);
return tms;
}
static TrustManager[] getTrustManagers()
throws NoSuchAlgorithmException, KeyStoreException
{
return getTrustManagers(null, null);
}
I have looked everywhere, but can't seem to find a solution please help.
I found my error, because do connection.setDoInput(true) it silencly sets my Requestmethod to post in version 4 which gives an error on the server causing it to return bad request.
apparently it does not set this in version 2, which explains why it does work there.
The following execute request method change fixed my code:
private String executeRequest(String urlAddress)
{
String responce = null;
String msg = null;
int error = 0;
try {
URL url = new URL(urlAddress);
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
SSLSocketFactory factory = SecureSocketFactory.getSSLSocketFactory();
connection.setSSLSocketFactory(factory);
connection.setHostnameVerifier(new Verifier());
if (method == RequestMethod.POST)
{
connection.setDoOutput(true);
connection.setRequestMethod("POST");
}
else
{
connection.setDoInput(true);
connection.setRequestMethod("GET");
}
msg = connection.getResponseMessage();
error = connection.getResponseCode();
if ("OK".equals(msg))
{
InputStream content = (InputStream) connection.getContent();
responce = convertStreamToString(content);
}
else
{
responce = "Error " + error;
}
connection.disconnect();
} catch (Exception e) {
responce = e.toString();
}
return responce;
}

Posting HTTPS form results in html 404 status code

I keep getting a HTML 404 reply from the server when I try to login via a httppost (https). Not sure if this is a cookie problem or something else. The code should be good as I have copied it from another activity. I need some help.
This is my current code:
public int postData(String usernamne, String password) {
String url = "https://domainname.com/nclogin.submit";
HttpPost httppost = new HttpPost(url);
try {
KeyStore trusted = null;
try {
trusted = KeyStore.getInstance("BKS");
} catch (KeyStoreException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
trusted.load(null, "".toCharArray());
MySSLSocketFactory sslf = null;
try {
sslf = new MySSLSocketFactory(trusted);
} catch (KeyManagementException e) {
Log.d(TAG, "Exception " + e);
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
Log.d(TAG, "Exception " + e);
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
Log.d(TAG, "Exception " + e);
// TODO Auto-generated catch block
e.printStackTrace();
}
sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("f_username", "myemail#address.com"));
nameValuePairs.add(new BasicNameValuePair("f_passwd", "mypassword"));
nameValuePairs.add(new BasicNameValuePair("f_method", "LOGIN"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", sslf, 443));
SingleClientConnManager cm = new SingleClientConnManager(httppost.getParams(), schemeRegistry);
// NEW API WONT ALLOW THIS IN THE MAIN THREAD! hence ASYNC
DefaultHttpClient client = new DefaultHttpClient(cm, httppost.getParams());
HttpResponse result = client.execute(httppost);
// Check if server response is valid
StatusLine status = result.getStatusLine();
Log.d(TAG, "STatus" + result.getStatusLine());
if (status.getStatusCode() != 200) {
throw new IOException("Invalid response from server: " + status.toString());
}
HttpEntity entity = result.getEntity();
InputStream is = entity.getContent();
if (is != null) {
is.close(); // release connection
}
String phpsessid = "";
// cookies from another blog
// http://stackoverflow.com/questions/4224913/android-session-management
List cookies = client.getCookieStore().getCookies();
if (cookies.isEmpty()) {
Log.d(TAG, "no cookies received");
} else {
for (int i = 0; i < cookies.size(); i++) {
// Log.d(TAG, "COOKIE-" + i + " " +
// cookies.get(i).toString());
if (cookies.get(i).toString().contains("PHPSESSID")) {
phpsessid = cookies.get(i).toString();
Log.d(TAG, "COOKIE FOR PHPSESSID - " + phpsessid);
}
}
} // end of blog
entity.consumeContent();
client.getConnectionManager().shutdown();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (CertificateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return 1;
} // end of postData()
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host,
port, autoClose);
}
#Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
I know the url is correct, as are the name value pairs, as I can login via a query string via a browser or via wget:
https://domainname.com/nclogin.submit?f_username=myemail#email.com&f_passwd=password&f_method=LOGIN
This results in a connection established and a redirect to my dashboard page.
The HTML code (source) from the login page can be viewed
here

Resources