0

I am new to Volley and OkHttp and I am trying to login to a website using OkHttp as the transport layer for Volley. Login needs to be done through SSL and has several redirects implemented.

OkHttp has been forced to not automatically follow redirects as I need to do this manually for this site (I think), but I am failing at the post request (I am not sure though).

The post requests needs some params provided like this:

source=AEM&target=IAM&URL=selfcare&login-form-type=pwd&username=user&userId=user&password=pass&rememberUsername=yes&button=

So it should be a StringRequest if I am not mistaken, furthermore I need to override the headers for all the requests like this:

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String>  params = new HashMap<String, String>();
params.put("Connection", "keep-alive");
params.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
params.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
return params;
}

I would be gratefull if someone could overlook my code, to see where I am going wrong. Once again, I am new to volley and okhttp, so downvoters pls be gentle.

Edit:

For anyone who has the same problem.

I finally managed to get a successfull login with the help of amoung the PersistentCookieStore (https://gist.github.com/franmontiel/ed12a2295566b7076161).

Also I needed to make a synchronized RequestQueue to be able to follow all the redirects manually. (this could be improved by using FutureRequest but it works, feel free to change the below working code to your needs.

Singleton class:

public class TestController extends Application {
    public static final String TAG = "VolleyPatterns";
    private RequestQueue mRequestQueue;
    private static TestController sInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }
    public static synchronized TestController getInstance() {
        return sInstance;
    }
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext(), new OkHttpStack());
        }
        return mRequestQueue;
    }
    public <T> void addToRequestQueue(Request<T> req, String tag) {
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        VolleyLog.e("Adding request to queue: %s", req.getUrl());
        getRequestQueue().add(req);
    }
    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);

        getRequestQueue().add(req);
    }
    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

OkHttpStack class (SSL allow all certs for testing purposes):

public class OkHttpStack extends HurlStack {
    private final OkUrlFactory okUrlFactory;

    public OkHttpStack() {
        this(new OkUrlFactory(getOkHttpClient()));
    }

    public OkHttpStack(OkUrlFactory okUrlFactory) {
        if (okUrlFactory == null) {
            throw new NullPointerException("Client must not be null.");
        }
        this.okUrlFactory = okUrlFactory;
    }

    private static OkHttpClient getOkHttpClient() {
        if (BuildConfig.DEBUG) {
            return getUnsafeOkHttpClient();
        } else {
            return new OkHttpClient();
        }
    }

    private static OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                    }
            };
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient okHttpClient = new OkHttpClient();
            okHttpClient.setFollowRedirects(false);
            okHttpClient.setSslSocketFactory(sslSocketFactory);
            okHttpClient.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {

        return okUrlFactory.open(url);
    }
}

MainActivity:

public class MainActivity extends AppCompatActivity {

private String LOGINURL = "https://www.test.com/testhandler/iam/authenticateuser/";
private static String redirectURL;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    CookieManager cmrCookieMan = new CookieManager(new PersistentCookieStore(this), CookiePolicy.ACCEPT_ALL);
    CookieHandler.setDefault(cmrCookieMan);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    final StringRequest postRequest = new StringRequest(Request.Method.POST, LOGINURL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    Log.d("Response", response);
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    redirectURL = null;
                    final int status = error.networkResponse.statusCode;
                    if (HttpURLConnection.HTTP_MOVED_PERM == status || status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_SEE_OTHER) {
                        redirectURL = error.networkResponse.headers.get("Location");
                        Log.e("Redirected to ", redirectURL);
                        Log.d("ERROR", "error => " + error.toString());
                        LoadFirst();
                        Log.w("1st ", "Link");
                    }
                }
            }
    ) {
        @Override
        public String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset=utf-8";
        }

        // this is the relevant method
        @Override
        public byte[] getBody() throws AuthFailureError {
            String httpPostBody ="username=yser&password=pass";
            try {
                httpPostBody = httpPostBody + URLEncoder.encode("", "UTF-8");
            } catch (UnsupportedEncodingException exception) {
                Log.e("ERROR", "exception", exception);
                return null;
            }
            return httpPostBody.getBytes();
        }
    };
    TestController.getInstance().addToRequestQueue(postRequest);
}

private void LoadFirst() {

    StringRequest stringRequest = new StringRequest(Request.Method.GET, redirectURL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    Log.e("Response:", response);
                }

            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            redirectURL = null;
            final int status = error.networkResponse.statusCode;
            if (HttpURLConnection.HTTP_MOVED_PERM == status || status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_SEE_OTHER) {
                redirectURL = error.networkResponse.headers.get("Location");
                Log.e("2nd Redirect to ", redirectURL);
                LoadSecond();
                Log.w("2nd ", "Link");
            }
        }

    });
    TestController.getInstance().addToRequestQueue(stringRequest);
}

private void LoadSecond() {

    StringRequest stringRequest = new StringRequest(Request.Method.GET, redirectURL,
            new Response.Listener<String>() {

                @Override
                public void onResponse(String s) {
                //Search the secretUserID in the response, which is only provided after successfull login
                    for (String line : s.split("\n")) {
                        if (line.contains("secretUserID")) {
                            String[] out = line.split("'");
                            String CustID = out[1].toString();
                            Log.w("secretUserID", CustID);
                        }
                    }
                    Log.w("3rd FINAL ", "Successfully logged in!");
                }
            }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e("Fatal error: ", error.toString());
            if (error instanceof TimeoutError) {
                // note : may cause recursive invoke if always timeout.
                Log.e("Timed out ", "retrying..");
                LoadSecond();
            }
        }

    });
    stringRequest.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 2,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    TestController.getInstance().addToRequestQueue(stringRequest);
}

}

Logcat:

03-23 16:19:46.791 5847-5878/test.com.example.buddy.myapplication D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
03-23 16:19:46.846 5847-5878/test.com.example.buddy.myapplication I/OpenGLRenderer: Initialized EGL, version 1.4
03-23 16:19:47.534 5847-5877/test.com.example.buddy.myapplication E/Volley: [1644] BasicNetwork.performRequest: Request at https://www.test.com/testhandler/iam/authenticateuser/ has been redirected to https://www.test.com/login.login/?url=%2Ftesthandler%2Fiam%2Fauthenticateuser%2F
03-23 16:19:47.538 5847-5847/test.com.example.buddy.myapplication E/Redirected to: https://www.test.com/login.login/?url=%2Fztesthandler%2Fiam%2Fauthenticateuser%2F
03-23 16:19:47.538 5847-5847/test.com.example.buddy.myapplication D/ERROR: error => com.android.volley.RedirectError
03-23 16:19:47.540 5847-5847/test.com.example.buddy.myapplication W/1st: Link
03-23 16:19:47.611 5847-5874/test.com.example.buddy.myapplication E/Volley: [1641] BasicNetwork.performRequest: Request at https://www.test.com/login.login/?url=%2Ftesthandler%2Fiam%2Fauthenticateuser%2F has been redirected to https://www.test.com/test/?selfcare
03-23 16:19:47.612 5847-5847/test.com.example.buddy.myapplication E/2nd Redirect to: https://www.test.com/test/?selfcare
03-23 16:19:47.612 5847-5847/test.com.example.buddy.myapplication W/2nd: Link
03-23 16:19:51.533 5847-5875/test.com.example.buddy.myapplication D/Volley: [1642] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] https://www.test.com/test/?selfcare 0xe5b1fae3 NORMAL 3> [lifetime=3920], [size=34928], [rc=200], [retryCount=0]
03-23 16:19:51.544 5847-5847/test.com.example.buddy.myapplication W/encryptedCustID: someUserID
03-23 16:19:51.545 5847-5847/test.com.example.buddy.myapplication W/3rd FINAL: Successfully logged in!
Simon
  • 1,691
  • 2
  • 13
  • 28
  • You are getting the request, and the `500` response. [Check the documentation for 500](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html), usually an error in the request or an not expected request. Copy the `https://www.test.com/login/?TAM_OP=login&USERNAME=unauthenticated&ERROR_CODE=0x00000000&URL=%2Ftest%2F%3Fselfcare&REFERER=&OLDSESSION=1` and try that in your network. (BTW, the classes seem correct at first glance) – Bonatti Mar 22 '16 at 15:08
  • @Bonatti, thx for responding. 500 internal server error, so I my post is not correct. I do not own the server so I guess it is the params or headers. The params are also not formatted like: 'source=AEM&target=IAM&URL=selfcare&login-form-type=pwd&username=user&userId=user&password=pass&rememberUsername=yes&button='. I don`t know how to do this in volley/okhttp. – Simon Mar 22 '16 at 15:14
  • `The params are also not formatted like`... How are they formatted? – zgc7009 Mar 22 '16 at 15:21
  • @zgc7009 Like, E/Params:: {password=pass, login-form-type=pwd, source=AEM, button=, username=user, userId=user, target=IAM, rememberUsername=yes, URL=selfcare} – Simon Mar 22 '16 at 15:22
  • 1
    That looks like a post body, you need to override getBody() in your request and add the parameters there. Look at this http://stackoverflow.com/questions/33573803/how-to-send-a-post-request-using-volley-with-string-body – zgc7009 Mar 22 '16 at 15:25
  • @zgc7009, ok thx for noticing, I will have a look. Any other errors you see? The headers are only included in the post request and not the get requests, does that make a difference? To obtain the correct set-cookies I mean, there are 2 which need to be grabbed. – Simon Mar 22 '16 at 15:30
  • 1
    @zgc7009 +1 for getting me on the right track, I edited my question with the working example. Thx again. – Simon Mar 23 '16 at 15:56
  • Glad you got things going. This stuff is tricky, lots of moving parts – zgc7009 Mar 23 '16 at 16:25

0 Answers0