I have an application that needs to be able to post to https with an authentication request and then a register request. Currently i am able to post my authentication request to https and it works fine. When i try to post my registration request to https i keep getting the server response saying that i need to authenticate. I am authenticating before i attempt to register.
The admin of the server said that i might not be preserving the session. I am new to doing stuff with android and java. And i am new to this https stuff. I was wondering if someone could help me out here, i do not know if that is the problem for sure or even how to preserve an https session in android.
Below is my code and any suggestions are greatly appreciated!!!! Thanks in advance!!
//my helper class
public class SmartDBHelper {
private static Context tThis;
private static SmartDBHelper sDBHObject;
private static String macAddress;
private static String ipAddress;
private static HttpsURLConnection https;
/* constructor, private prevents any other class from instantiating */
private SmartDBHelper() {
}
public static synchronized SmartDBHelper getSDBHObject() {
if(sDBHObject == null) {
sDBHObject = new SmartDBHelper();
}
return sDBHObject;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public static synchronized void setSmartContext(SmartApp smartApp) {
tThis = (Context) smartApp;
}
private static synchronized void setMACIPAddress() {
WifiManager wifiMan = (WifiManager) tThis.getSystemService (tThis.WIFI_SERVICE);
WifiInfo wifiInf = wifiMan.getConnectionInfo();
macAddress = wifiInf.getMacAddress().replace(':', '-');
ipAddress = wifiMan.getDhcpInfo().toString();
int startIndex = ipAddress.indexOf(' ');
int endIndex = ipAddress.indexOf(' ', startIndex + 1);
ipAddress = ipAddress.substring(startIndex + 1, endIndex);
}
/* this function is to authenticate with the database
* it returns the id_subject, if it is greater than 0
* authentication was successful.
*/
public static synchronized int authenticate() throws MalformedURLException, ProtocolException, IOException {
Map<String, String> tempMap = new LinkedHashMap<String, String>();
tempMap.put((String) tThis.getResources().getText(R.string.postAction), (String) tThis.getResources().getText(R.string.postAuthenticate));
tempMap.put((String) tThis.getResources().getText(R.string.authUName), "username");
tempMap.put((String) tThis.getResources().getText(R.string.authPWord), "password");
String tempUrl = "https://ipaddress/health_monitoring/admin.php";
return Integer.parseInt(post(tempUrl, tempMap));
}
/* this function is to register the server to the database
* not sure of return value
*/
public static synchronized int registerServer(String nameOfServer, String description) throws MalformedURLException, ProtocolException, IOException {
setMACIPAddress();
Map<String, String> tempMap = new LinkedHashMap<String, String>();
tempMap.put((String) tThis.getResources().getText(R.string.postAction), (String) tThis.getResources().getText(R.string.postAddServer));
tempMap.put((String) tThis.getResources().getText(R.string.addServerName), "Phone");
tempMap.put((String) tThis.getResources().getText(R.string.addServerDescription), "Android");
tempMap.put((String) tThis.getResources().getText(R.string.addServerURL), "");
tempMap.put((String) tThis.getResources().getText(R.string.addServerIPAddress), ipAddress);
tempMap.put((String) tThis.getResources().getText(R.string.addServerMAC), macAddress);
String tempUrl = "https://ipaddress/health_monitoring/admin.php";
return Integer.parseInt(post(tempUrl, tempMap));
}
// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
/**
* Trust every server - dont check for any certificate
*/
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
private static String post(String urlString, Map formParameters)
throws MalformedURLException, ProtocolException, IOException {
DataOutputStream ostream = null;
trustAllHosts();
URL tempUrl;
StringBuffer buf = new StringBuffer();
if(formParameters != null) {
Set parameters = formParameters.keySet();
Iterator it = parameters.iterator();
for(int i = 0, paramCount = 0; it.hasNext(); i++) {
String parameterName = (String) it.next();
String parameterValue = (String) formParameters.get(parameterName);
if(parameterValue != null) {
parameterValue = URLEncoder.encode(parameterValue);
if(paramCount > 0) {
buf.append("&");
}
buf.append(parameterName);
buf.append("=");
buf.append(parameterValue);
++paramCount;
}
}
}
urlString = urlString + "?" + buf;
Log.v("smartdbhelper url string", urlString);
tempUrl = new URL(urlString);
https = (HttpsURLConnection) tempUrl.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
Log.v("smartdbhelper adding post parameters", https.toString());
https.setRequestMethod("POST");
https.setDoInput(true);
https.setDoOutput(true);
ostream = new DataOutputStream(https.getOutputStream());
ostream.writeBytes(buf.toString());
if( ostream != null ) {
ostream.flush();
ostream.close();
}
Object contents = https.getContent();
InputStream is = (InputStream) contents;
StringBuffer buf2 = new StringBuffer();
int c;
while((c = is.read()) != -1) {
buf2.append((char)c);
Log.v("smartdbhelper bugger", buf2.toString());
}
//https.disconnect();
return buf2.toString();
}
}
It sounds like you probably need to handle cookie headers to preserve the session. If that's the case this isn't specific to HTTPS. You'll need to find the Set-Cookie response header when you make the first request. Then every request after that you'll pass those through a Cookie request header. Here's a basic example that you can adapt for your case:
// your first request that does the authentication
URL authUrl = new URL("https://example.com/authentication");
HttpsURLConnection authCon = (HttpsURLConnection) authUrl.openConnection();
authCon.connect();
// temporary to build request cookie header
StringBuilder sb = new StringBuilder();
// find the cookies in the response header from the first request
List<String> cookies = authCon.getHeaderFields().get("Set-Cookie");
if (cookies != null) {
for (String cookie : cookies) {
if (sb.length() > 0) {
sb.append("; ");
}
// only want the first part of the cookie header that has the value
String value = cookie.split(";")[0];
sb.append(value);
}
}
// build request cookie header to send on all subsequent requests
String cookieHeader = sb.toString();
// with the cookie header your session should be preserved
URL regUrl = new URL("https://example.com/register");
HttpsURLConnection regCon = (HttpsURLConnection) regUrl.openConnection();
regCon.setRequestProperty("Cookie", cookieHeader);
regCon.connect();
Related
I have create Java Classes from the DHL WSDL
https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/2.2/geschaeftskundenversand-api-2.2.wsdl.
Now i have all Classes, but no Authentifaction Class.
I try this
GKVAPIServicePortTypeProxy port2 = new GKVAPIServicePortTypeProxy();
port2.setEndpoint("https://cig.dhl.de/services/sandbox/soap");
CreateShipmentOrderRequest sh = new CreateShipmentOrderRequest();
//Setting up shipment;
.. and so on
CreateShipmentOrderResponse chr = port2.createShipmentOrder(sh);
But only what i get is, "(401)Authorization Required"
How can i set my Authentifiaction ?
Hi I h had fixed the 401 problem with adding of the ssl certificate from DHL to my application truststore.
But I have the problem that I missing to add the Authentification block to the request.
<soapenv:Header>
<cis:Authentification>
<cis:user>user</cis:user>
<cis:signature>password</cis:signature>
</cis:Authentification>
</soapenv:Header>
My try to adding this block resulting in a 'org.quartz.jobexecutionexception: de.vps.icms.exceptions.icmsscriptingexception: java.lang.noclassdeffounderror: org/apache/axis2/saaj/soapenvelopeimpl'exception.
Some idea what I did wrong?
Here the Code:
public class WSClient {
public WSClient() {
try {
GKVAPIServicePortType port = prepareService();
String b = BWIConstants.SYSPARAM_DHL_WS_URL;
CreateShipmentOrderRequest createShipmentOrderRequest = new CreateShipmentOrderRequest();
CreateShipmentOrderResponse createShipmentOrderResponse =
port.createShipmentOrder(createShipmentOrderRequest);
createShipmentOrderResponse.getStatus();
} catch (Exception e) {
e.printStackTrace();
}
}
private GKVAPIServicePortType prepareService() throws MalformedURLException {
// get Service stub
String pathToClassFolder = getClass().getResource("/").toString();
String fullwsdlFilePath = pathToClassFolder + "/" + "geschaeftskundenversand-api-2.2.wsdl";
URL wsdlLocation = new URL(fullwsdlFilePath);
GVAPI20De service = new GVAPI20De(wsdlLocation);
// get Service Port
GKVAPIServicePortType port = service.getPort(GKVAPIServicePortType.class);
// overwrite Endpoint
Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://cig.dhl.de/services/sandbox/soap");
// overwrite BasicAuth Username and Password
// requestContext.put(BindingProvider.USERNAME_PROPERTY, cigUser);
// requestContext.put(BindingProvider.PASSWORD_PROPERTY, cigPass);
// Add authentication Handler
Binding binding = ((BindingProvider) port).getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
handlerChain.add(
new AuthenticationHandler(BWIConstants.SYSPARAM_DHL_WS_USER, BWIConstants.SYSPARAM_DHL_WS_SIGNATURE));
binding.setHandlerChain(handlerChain);
return port;
}
}
public class AuthenticationHandler implements SOAPHandler<SOAPMessageContext> {
private String USER = "";
private String PASSWORD = "";
public AuthenticationHandler(final String user, final String password) {
USER = user;
PASSWORD = password;
}
/**
* {#inheritDoc}
*/
public void close(final MessageContext context) {
// nothing to do
}
/**
* {#inheritDoc}
*/
public Set<QName> getHeaders() {
// nothing to do
return null;
}
/**
* {#inheritDoc}
*/
public boolean handleFault(final SOAPMessageContext context) {
// nothing to do
return true;
}
/**
* {#inheritDoc}
*/
public boolean handleMessage(final SOAPMessageContext context) {
if (isOutboundMessage(context)) {
try {
// get/create the map of HTTP headers
Map<Object, Object> headers = (Map<Object, Object>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers == null) {
headers = new HashMap<Object, Object>();
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
// add custom HTTP header (deactivate HTTP keepAlive)
String headerName = "Connection";
List<String> headerValues = new ArrayList<String>();
headerValues.add("Close");
headers.put(headerName, headerValues);
SOAPMessage message = context.getMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPHeader header;
if (envelope.getHeader() == null) {
header = envelope.addHeader();
} else {
header = envelope.getHeader();
}
// add the Authentification element
SOAPElement auth = header.addHeaderElement(
envelope.createName("Authentification", "cis", "http://dhl.de/webservice/cisbase"));
SOAPElement user =
auth.addChildElement(envelope.createName("user", "cis", "http://dhl.de/webservice/cisbase"));
user.setValue(USER);
SOAPElement signature =
auth.addChildElement(envelope.createName("signature", "cis", "http://dhl.de/webservice/cisbase"));
signature.setValue(PASSWORD);
SOAPElement type =
auth.addChildElement(envelope.createName("type", "cis", "http://dhl.de/webservice/cisbase"));
type.setValue("0");
// save changes
message.saveChanges();
} catch (SOAPException ex) {
throw new RuntimeException("Failed to add SOAP headers for authentication.", ex);
}
}
return true;
}
private boolean isOutboundMessage(final MessageContext context) {
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
return outboundProperty.booleanValue();
}
}
Using basic authentication, you would first Base64 encode your username:password - there's online sites that will do it but beware as likely not a good idea to do it if it refers to DHL in anyway, e.g. they could swipe your credentials.
You then get the Request Context of the port, create a map of the headers and add an Authorization header. Finally you add that back to the request context.
Example:
Note, I purposely generated bad base64 encoding so you would likely not be able to decode it and see it properly formatted with the "username:password"
GVAPI20De service1 = new GVAPI20De();
GKVAPIServicePortType port2 = service1.getGKVAPISOAP11Port0();
CreateShipmentOrderRequest sh = new CreateShipmentOrderRequest();
//Setting up shipment;
Map<String, Object> req_ctx = ((BindingProvider)port2).getRequestContext();
//you may not need this and can try commenting it out
req_ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://cig.dhl.de/cig-wsdls/com/dpdhl/wsdl/geschaeftskundenversand-api/2.2/geschaeftskundenversand-api-2.2.wsdl");
//optional timeout
req_ctx.put("javax.xml.ws.client.connectionTimeout", "60000");
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Authorization", Collections.singletonList("Basic c3gh567sd4689k11lg=="));
req_ctx.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
CreateShipmentOrderResponse chr = port2.createShipmentOrder(sh)
This is my Https client
public String sendHttpsRequest(String httpsUrl, HttpMethod method,
String body, Map<String, String> headers) {
String response = "";
int responseCode = 0;
HttpsURLConnection conn = null;
try {
URL url = new URL(httpsUrl);
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod(method.toString());
for (Map.Entry<String, String> entry : headers.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{
new javax.net.ssl.X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
#Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
}
}, null);
conn.setSSLSocketFactory(context.getSocketFactory());
String param = body;
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(param);
wr.flush();
wr.close();
responseCode = conn.getResponseCode();
InputStream in = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
response += line;
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(conn != null) {
conn.disconnect();
}
}
return responseCode == 200?response:Integer.toString(responseCode);
}
but for some reason it gives me a "405 Method not allowed" when I try to conncet to https://httpbin.org/get with following parameters.
TreeMap<String, String> map = new TreeMap<>();
map.put("Content-Type", "application/json");
System.out.println(new HttpLiveTest().sendHttpsRequest("https://httpbin.org/get" , HttpMethod.GET, "", map));
I also tried to connect to it through SoapUI with same parameters and it worked there.
I think the certificate that i'm using from Spring might be the problem but I wouldnt know how to solve that issue and why whould it answer with an 405?
Using Wireshark to look at the package didnt work because of TLS
Arnaud said: setDoOutput(true) may force the method to be POST
hes right.
user7236363 wrote:
java.net.ProtocolException: cannot write to a URLConnection if doOutput=false - call setDoOutput(true) is what im getting when i wont set it on true
he is also right.
Big picture:
What you want to do most of the time is a HTTP GET and that passes arguments in on the url - it doesnt requre any bytes to be written after the url so setting the Connection.setDoOutput(true) is not needed at all, hence dont do it when you want to do a GET.
Between the Connection.setRequestProperty(String Key, String Value) and the URL itself you should have everthing you need to make a properly formatted GET request.
I had a very simular problem and the root of it was me setting setDoOutput(true) and not realizing that it had a side effect that i didnt realize (ie setting the request method to post).
First,
I've searched a lot to find a solution but were not able to find an appropriate one.
Environment
(productive) Mongoose WebServer replies to simple GET-requests (all data are transmitted via QueryString)
Apache HttpClient (single instance!) used to make hundreds of thousands single requests sequentially.
Apache HttpClient interacting with mongoose works quite well
// after each request
getMethod.releaseConnection();
...
Problem
(Mock) implementation of WebServer with Sun HttpServer works fine with FireFox / Curl
Using Apache HttpClient as with running against productive Server, performance is horrible (~ 1 request/second) on client
Using Apache HttpClient with following code found on the net results in
vast performance gain on client
resource waste due to as many open sockets in CLOSE_WAIT state as requests processed (until no more FDs ara available!)
Code:
HttpConnectionManager mgr = httpClient.getHttpConnectionManager();
if (mgr instanceof SimpleHttpConnectionManager) {
((SimpleHttpConnectionManager)mgr).shutdown();
}
Obviously I am mising something in the http server implementation, which causes this extreme "sloweness"
Any hint/help is appreciated.
Thanks in advance!
Code
HttpServer
public static void main(String[] args) throws Exception {
//System.setProperty("sun.net.httpserver.maxIdleConnections", "10");
//System.setProperty("sun.net.httpserver.idleInterval", "2000");
HttpServer server = HttpServer.create();
server.bind(new InetSocketAddress("localhost", 11111), -1);
InetSocketAddress addr = server.getAddress();
HttpContext contextSearch = server.createContext("/search.to",
new TrufflesSearchHandler());
contextSearch.getFilters().add(new ParameterFilter());
server.setExecutor(null); // creates a default executor
server.start();
}
HttpHandler
static class SearchHandler implements HttpHandler {
private JSONParser jsonParser = new JSONParser();
public void handle(HttpExchange exchange) throws IOException {
Map<String, Object> params = (Map<String, Object>) exchange
.getAttribute("parameters");
String expectedResponse = "";
int expectedHitPlace = -1;
try {
expectedResponse = (String) params.get("expectedResponse");
expectedHitPlace = Integer.parseInt((String) params
.get("expectedHitPlace"));
} catch (Exception e) {
e.printStackTrace();
}
JSONArray resultArray = null;
try {
resultArray = (JSONArray) jsonParser.parse(new String(Base64
.decodeBase64(expectedResponse)));
fillResponseWithDummyData(resultArray, expectedHitPlace);
} catch (ParseException e) {
e.printStackTrace();
}
String response = "{ \"results\": " + resultArray + "}";
Headers headers = exchange.getResponseHeaders();
headers.add("Connection", "keep-alive");
headers.add("Content-Type", "text/plain");
headers.add("Content-length", "" + response.getBytes().length);
// headers.add("Keep-Alive", "timeout=5 max=10");
exchange.sendResponseHeaders(200, 0);
// exchange.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(response.getBytes());
os.flush();
os.close();
// exchange.close();
}
ParameterFilter
#SuppressWarnings("restriction")
public class ParameterFilter extends Filter {
#Override
public String description() {
return "Parses the requested URI for parameters";
}
#Override
public void doFilter(HttpExchange exchange, Chain chain)
throws IOException {
parseGetParameters(exchange);
parsePostParameters(exchange);
chain.doFilter(exchange);
}
private void parseGetParameters(HttpExchange exchange)
throws UnsupportedEncodingException {
Map<String, Object> parameters = new HashMap<String, Object>();
URI requestedUri = exchange.getRequestURI();
String query = requestedUri.getRawQuery();
parseQuery(query, parameters);
exchange.setAttribute("parameters", parameters);
}
private void parsePostParameters(HttpExchange exchange)
throws IOException {
if ("post".equalsIgnoreCase(exchange.getRequestMethod())) {
#SuppressWarnings("unchecked")
Map<String, Object> parameters =
(Map<String, Object>)exchange.getAttribute("parameters");
InputStreamReader isr =
new InputStreamReader(exchange.getRequestBody(),"utf-8");
BufferedReader br = new BufferedReader(isr);
String query = br.readLine();
parseQuery(query, parameters);
}
}
private void parseQuery(String query, Map<String, Object> parameters)
throws UnsupportedEncodingException {
String encoding = System.getProperty("file.encoding");
if (query != null) {
String pairs[] = query.split("[&]");
for (String pair : pairs) {
String param[] = pair.split("[=]");
String key = null;
String value = null;
if (param.length > 0) {
key = URLDecoder.decode(param[0],
encoding);
}
if (param.length > 1) {
value = URLDecoder.decode(param[1],
encoding);
}
if (parameters.containsKey(key)) {
Object obj = parameters.get(key);
if(obj instanceof List<?>) {
List<String> values = (List<String>)obj;
values.add(value);
} else if(obj instanceof String) {
List<String> values = new ArrayList<String>();
values.add((String)obj);
values.add(value);
parameters.put(key, values);
}
} else {
parameters.put(key, value);
}
}
}
}
}
I'm building an application that needs to login to a certain page and make a navigation. I can login, provided that the response contains a string that identifies it. But when I navigate to the second page, I can't see the page as a logged user, only as anonymous.
I'll provide my code:
import java.net.*;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
import java.io.*;
import java.util.*;
public class PostTest {
static HttpsURLConnection conn = null;
static String sessionId = null;
private static class DefaultTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
public static void main(String[] args) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
String data = URLEncoder.encode("txtUserName", "UTF-8") + "=" + URLEncoder.encode(/*username*/, "UTF-8");
data += "&" + URLEncoder.encode("txtPassword", "UTF-8") + "=" + URLEncoder.encode(/*password*/", "UTF-8");
data += "&" + URLEncoder.encode("envia", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8");
connectToSSL(/*login url*/);
//throws java.lang.IllegalStateException: Already connected
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
String resposta = "";
while((line = rd.readLine()) != null) {
resposta += line + "\n";
}
System.out.println("valid login -> " + resposta.contains(/*string that assures me I'm looged in*/));
connectToSSL(/*first navigation page*/);
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch(Exception e) {
e.printStackTrace();
}
}
private static void connectToSSL(String address) {
try {
URL url = new URL(address);
conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
if(sessionId == null) {
sessionId = conn.getHeaderField("Set-Cookie");
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
Any further information, just ask.
In connectToSSL, you are opening a new connection each time. In second connection, it will not have any attribute from first connection.
You may want to set get some token/cookie value after fist login connection and use the same in subsequent calls by e.g.
After first connection:
String sessionId = conn.getHeaderField("Set-Cookie");
In subsequent connections:
conn.setRequestProperty("Cookie", sessionId );
Take a look at the Apache Commons project HttpClient. It will help you do what you are trying to accomplish. You need sometime much more complex than a URL class. It needs to maintain a lot of information to go from one authentication request to subsequent authenticated requests.
The site you're accessing probably uses cookies to identify logged in sessions. You'll need to save cookies set on the first request and send them on subsequent requests.
If you're using HttpsUrlConnection, see Cookie Management and java.net.CookieManager. Another choice would be Apache HttpComponents which do cookie management by default.
http is a stateless protocol.
to retain state( sessions) store the cookies received from the server.
List<String> cookies = conn.getHeaderFields().get("Set-Cookie");
send them to server in subsequent requests
for (String cookie : cookies) {
//remove expires and path from cookie
String cookieValue=cookie.substring(0, cookie.indexOf(';');
conn.addRequestProperty("Cookie",cookieValue);
}
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
I have a Java web app that posts items to our users facebook walls, when the user initially signs up we get a 60 day access_token which is persisted to our database, now that the offline_access is be removed I using our 'Login with facebook' button to update the tokens when the user logs into our website, this is all good as they will typically visit more than 60 days apart.
I have implemented the above and it works well...but then I found that the access tokens that are being generated from the login action expire after 1 hour....obviously not good a we cant post to their walls while they are away.
The code below demonstrates how we are getting the tokens via the signed_request method (in Java SEAM App), this works ok, but the tokens are short-lived
Can anyone suggest how to ensure the tokens are the 60-day type
Thanks
public void loginWithFacebook(){
accessToken = null;
try {
accessToken = FaceBookSecurity.getFBAccessToken();
} catch (Exception e) {
log.error("Error getting FB access token: "+e);
}
FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
com.restfb.types.User facebookUser = facebookClient.fetchObject("me", com.restfb.types.User.class);
facebookEmail = facebookUser.getEmail();
if (facebookEmail != null) {
new RunAsOperation(true) {
public void execute() {
user = ((UserDAO)Component.getInstance("userDAO")).findByEmail(StringUtils.lowerCase(facebookEmail));
if (user != null && user.getFacebookToken() != null && !accessToken.equals(user.getFacebookToken())) {
user.setFacebookToken(accessToken);
log.error("FB: updating "+user.getFirstname()+" "+user.getSurname()+"s FB token to: "+accessToken);
}
}
}.run();
if (user != null) {
//set the user as logged in
return;
}
}
messagePoster.postPopupErrorMessage(messages.get("facebookLoginFailed"));
}
public static String getFBAccessToken()
throws Exception {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
Cookie fbCookie = getFBCookie(request);
String fbCookieValue = fbCookie.getValue();
String[] stringArgs = fbCookieValue.split("\\.");
String encodedPayload = stringArgs[1];
JsonObject data;
try{
String payload = base64UrlDecode(encodedPayload);
// gets the js object from the cookie
data = new JsonObject(payload);
}catch (Exception e){
return "";
}
String authUrl = getAuthURL(data.getString("code"));
URL url = new URL(authUrl);
URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(),
url.getQuery(), null);
String result = readURL(uri.toURL());
String[] resultSplited = result.split("&");
return resultSplited[0].split("=")[1];
}
// creates the url for calling to oauth.
public static String getAuthURL(String authCode) {
String url = "https://graph.facebook.com/oauth/access_token?client_id="
+ FacebookApp.appId
+ "&redirect_uri=&client_secret="
+ FacebookApp.appSecret + "&code="
+ authCode;
return url;
}
// reads the url.
private static String readURL(URL url) throws IOException {
InputStream is = url.openStream();
InputStreamReader inStreamReader = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(inStreamReader);
String s = "";
int r;
while ((r = is.read()) != -1) {
s = reader.readLine();
}
reader.close();
return s;
}
private static String base64UrlDecode(String input){
return new String(Base64.decodeBase64(input.getBytes()));
}
If all you need is to post to the user's wall, then you can also use app_access_token provided you have asked for publish_stream permission.
You can call :
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&client_secret=YOUR_APP_SECRET
&grant_type=client_credentials
Read this.
Edit: app access_tokens do not expire until the app secret is reset.