Symfony2 firewall issue Android - android

Let me explain my situation, I developed a complete backend for an Android application in Symfony2.1 that works perfectly, now I'm trying to create the Android app part, for that I created a firewall with http_basic authentication that ensures that my users are correctly authenticated and authorized, I actually can use my app and be logged, but if I try to retrieve any page behind the firewall a get a 404 error.
I don't want to use any external bundle, I just want to send my user/pass on every request since my app makes just three httpclient calls but I don't know hoy to get access granted on every request.
Here is part of my code, feel free to ask :)
Thanks in advance!
My Android http call:
#Override protected String doInBackground(Void... arg0) {
HttpClient httpClient = new DefaultHttpClient();
// construir peticion get
HttpGet httpGet = new HttpGet("http://www.somewebsite.com/api/login/");
httpGet.addHeader(BasicScheme.authenticate(
new UsernamePasswordCredentials(loguser, passw), "UTF-8",
false));
try {
response = httpClient.execute(httpGet);
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
builder = new StringBuilder();
for(String line = null; (line = reader.readLine()) != null;){
builder.append(line).append("\n");
}
} catch (Exception e) {
e.printStackTrace();
alert("Error de protocolo", "Lo sentimos, ha ocurrido un error");
}
return builder.toString();
}
My firewall
api:
pattern: ^/api/.*
provider: app_user
http_basic:
realm: "API"
access_control:
- { path: ^/api-registro/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/.*, role: ROLE_API }
providers:
app_user:
entity: { class: Alood\BackBundle\Entity\Usuario, property: user }
encoders:
Alood\BackBundle\Entity\Usuario: plaintext
My Controller
public function apiLoginAction()
{
$peticion = $this->getRequest();
$sesion = $peticion->getSession();
$usuario = $this->get('security.context')->getToken()->getUser();
$error = $peticion->attributes->get(SecurityContext::AUTHENTICATION_ERROR,
$sesion->get(SecurityContext::AUTHENTICATION_ERROR));
$securityContext = $this->container->get('security.context');
if( $securityContext->isGranted('IS_AUTHENTICATED_FULLY')){
$texto["user"] = $usuario->getUser();
return new JsonResponse($texto);
}
}
Note: If I repeat the same steps in a different function of my controller I get a problem in my android app and I don't know how to solve this.

It happened to be a typo issue in my routing.yml so if its useful for somebody I must say this works properly.

Related

How to make a HTTP/POST request in Kotlin (Android) to simple server?

Hello I am trying to begin an Android app in Kotlin. I have been trying to find a way to simply send and receive data from an android app to a simple HTTP server I made on my computer. The idea I am hoping is just make an app with a text box on it and a send button. When I press the send button it sends it to the simple http server (whether I use IP address or URL isn't Important)
This is just simply a proof of concept that I can make my own simple HTTP Server and get the app to send and receive from it.
I am essentially trying to do a server-client architecture between an android app and a computer. I can get this concept to work between two computer applications (python, java, C++ etc) but not how to do it in android. I keep looking for other answers on here but still come up short.
to be specific do I need enable certain features within the configurations file or a library that will allow the task to be done in the background?
Thank you for your help in advance.
If you want to connect of server for sending requests (POST and GET) then follow this code
public void callApi(String urls,String calledFor) {
try {
HttpGet httppost = new HttpGet(urls);
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(httppost);
int status = response.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
JSONObject jsono = new JSONObject(data);
JSONObject json = jsono.getJSONObject("data");
}
} catch (ParseException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
ktor is a wonderful HTTP client that you can use for Android. It is developed by JetBrains, who are also authors of Kotlin, so it takes advantage of the features of the language:
You will need to add the ktor client for Android in build.gradle:
implementation "io.ktor:ktor-client-android:$ktor_version"
Then set up your client like this:
val client = HttpClient(Android) {
// setting these properties is optional; you don't need to if you wish to use the defaults
engine {
connectTimeout = 100_000
socketTimeout = 100_000
}
}
At last you can make HTTP requests like so (example from here): (the use method is to automatically close it at the end, make sure you read about releasing resources)
val resp: String = client.use {
val htmlContent = it.get<String>("https://en.wikipedia.org/wiki/Main_Page")
println(htmlContent)
// same as
val content: String = it.get("https://en.wikipedia.org/wiki/Main_Page")
content
}
Post Api request Using okHttp in Kotlin (Android)
follow steps
You will need to add the dependencies in build.gradle(:app)
implementation("com.squareup.okhttp3:okhttp:4.9.0")
request code here
fun runPostApi() {
var url = "https://reqres.in/api/users"
// add parameter
val formBody = FormBody.Builder().add("name", " Parker")
.build()
// creating request
var request = Request.Builder().url(url)
.post(formBody)
.build()
var client = OkHttpClient();
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
println(response.body?.string())
}
override fun onFailure(call: Call, e: IOException) {
println(e.message.toString())
}
})}
for more information link here below
https://square.github.io/okhttp/recipes/

Recieving HTML file as responce instead of JSON Object through get request

I am developing an android app where user logs on to his/her account. After logging in I will receive XSRF token and Laravel Session Id to recognise the specific user. I have to send these tokens for every request I send to the API's to get the appropriate information. But when I am sending the required details as shown in the image, I am getting HTMl file as response instead of getting JSON Object. I was seriously stuck at this problem. Correct Solution may take forward the whole app.
class RegisterConnection extends AsyncTask<String,String,JSONObject> {
protected JSONObject doInBackground(String... arg0) {
JSONObject output = new JSONObject();
DefaultHttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 5000); //Timeout Limit
HttpResponse response = null;
try {
HttpGet get = new HttpGet(statsURL);
get.setHeader("Accept", "application/json");
CookieStore store = new BasicCookieStore();
BasicClientCookie cookie1 = new BasicClientCookie("XSRF-TOKEN", XSRF);
BasicClientCookie cookie2 = new BasicClientCookie("laravel_session", laravel);
store.addCookie(cookie1);
store.addCookie(cookie2);
client.setCookieStore(store);
response = client.execute(get);
if(response!=null){
InputStream in = response.getEntity().getContent();
String resultstring = Utilities.convertStreamToString(in);
Log.i("Result1", resultstring);
output = new JSONObject(resultstring);
Log.i("Result2", output.toString());
}
} catch(Exception e) {
e.printStackTrace();
try {
output.put("sai","error");
Log.i("MainActivity", output.toString());
} catch (JSONException e1) {
e1.printStackTrace();
}
return output;
}
return output;
}
These are the server requirements
http://imgur.com/OY9Q673
This is the Output received
http://imgur.com/IB5AEcT
As far as I can tell, there is nothing wrong with your Android client code.
You are getting HTML from the server so the main reason could be that your Laravel server is rendering the views and sending you back html instead of JSON. Instead of rendering the views on the server, you should send JSON response on your Laravel server side.
Add Jsoup dependency in your gradle file
implementation 'org.jsoup:jsoup:1.11.2'
Document document = Jsoup.parse("http://imgur.com/IB5AEcT");
Elements el = doc.select("button");
Log.i("..........",""+el.attr("data-invite-details"));
Jsoup tutorial
http://jsoup.org/apidocs/org/jsoup/Jsoup.html

Android Studio app using Django back-end login authentication?

I've recently been working on an Android app using Android Studio which is using a Django backend. The web application is already in place I just want to make the app in Android for it.
The problem I am running in to, which is mostly because I'm new to app development, is the login authentication. I've researched on this topic here and I understand theoretically how I should go about doing this, but I have not been successful in logging in from my app.
The problem I have is this:
I get a csrf token authentication failure. It states that the cookie is not set. I understand that a post request will return this.
I am always getting a success transition in my doPost method.
I currently am lost in how to check if I have actually logged in or not. And the only solution I thought of for the cookie not being set is to do a Get request, parse the cookie as a string and pass that in to the post request. But I'm not sold on it being the best strategy. The bigger problem is not being able to tell if I have actually logged in or not. How can I check that? I have read posts on kind of explaining how to do this but as a beginner it is hard to translate that to code. How do I check if the user was actually authenticated? Any and all help is appreciated.
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
private final String mEmail;
private final String mPassword;
UserLoginTask(String email, String password) {
mEmail = email;
mPassword = password;
}
#Override
protected Boolean doInBackground(Void... params) {
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("username", mEmail));
postParameters.add(new BasicNameValuePair("password", mPassword));
String response = null;
String get_response = null;
try
{
response = SimpleHttpClient.executeHttpPost(localLoginUrl, postParameters);
Log.d("Login Activity","Post Response is: " + response);
}
catch (Exception e)
{
Log.d("Login Activity","Error is: " + e.toString());
e.printStackTrace();
return false;
}
return true;
}
public static String executeHttpPost(String url,
ArrayList<NameValuePair> postParameters) throws Exception {
BufferedReader in = null;
try {
HttpClient client = getHttpClient();
HttpPost request = new HttpPost(url);
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters);
request.setEntity(formEntity);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
String result = sb.toString();
return result;
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The Django view:
def login_view(request): # Login page view
form = login_form()
if request.method == 'POST':
form = login_form(request.POST)
if form.is_valid(): # check if form is valid
user = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']) # authenthicate the username and password
login(request, user) # login the user
# Once logged in redirect to home page
response = HttpResponseRedirect("/"+some_user_url+"/home")
print "USER KEY IS: %s" % some_user_key
response.set_cookie('some_user_key', value=some_user_value, max_age=some_max_age, secure=SESSION_COOKIE_SECURE, httponly=False)
return response
else:
form = login_form() # Display empty form
return render(request, "login.html", { # loads the template and sends values for the template tags
'form': form,
})
I know the questions was asked quite a long time ago but, since there's no answer, and I'm working quite intensively with Django recently, I thought to share my very basic knowledge, hoping it will be of help for others.
The way you are dealing with the CSRF token is the correct one: first you perform a get of the login page which will give you the CSRF token in the cookie. You store the cookie and the CSRF token and you embed them in the following POST request, together with authentication data. If you get a 200 OK from the server it already means you correctly used the CSRF token, and this is an awesome start :)
In order to troubleshoot whether the user has actually logged in or not, that is whether it's credentials were accepted, you can print out the payload of the HTTP response you obtained from the server.
I use a function which prints me the response of the server in case I get an error code greater than 400. The code is the following:
public static boolean printHTTPErrorMsg(HttpURLConnection c) {
boolean error = false;
StringBuilder builder = new StringBuilder();
try {
builder.append(c.getResponseCode());
builder.append("\n");
builder.append(c.getResponseMessage());
System.out.println("RESPONSE CODE FROM SERVER");
System.out.println(builder);
InputStream _is;
if(c.getResponseCode()>=400){
error = true;
_is = c.getErrorStream();
final BufferedReader reader = new BufferedReader(
new InputStreamReader(_is));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return error;
}
You need to tweak it because when you get a 200 OK from the server, there's no ErrorStream but simply an InputStream. So if you change your if condition to =200 and replace the getErrorStream() with getInputStream() you'll see in the log what is actually the content of the response of the server. Typically, if the login failed, the response will contain most likely the HTML code of the login page with the error message saying you provided wrong credentials.
Hope this helps

Android http testing with Robolectric

I have an Android app where the main part of the app is the APIcalls.java class where I make http requests to get data from server an display the data in the app.
I wanted to create unit test for this Java class since it's the most part of the app. Here is the method for getting the data from server:
StringBuilder sb = new StringBuilder();
try {
httpclient = new DefaultHttpClient();
Httpget httpget = new HttpGet(url);
HttpEntity entity = null;
try {
HttpResponse response = httpclient.execute(httpget);
entity = response.getEntity();
} catch (Exception e) {
Log.d("Exception", e);
}
if (entity != null) {
InputStream is = null;
is = entity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
reader.close();
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
httpget.abort();
throw e;
} finally {
is.close();
}
httpclient.getConnectionManager().shutdown();
}
} catch (Exception e) {
Log.d("Exception", e);
}
String result = sb.toString().trim();
return result;
I thought I can make simple API calls from the tests like this:
api.get("www.example.com")
But every time I make some http calls from the tests, I get an error:
Unexpected HTTP call GET
I know I am doing something wrong here, but can anyone tell me how can I properly test this class in Android?
Thank you for all your answers but I found what I was looking for.
I wanted to test real HTTP calls.
By adding Robolectric.getFakeHttpLayer().interceptHttpRequests(false);
you tell Robolectric not to intercept these requests and it allows you to make real HTTP calls
Robolectric provides some helper methods to mock http response for DefaultHttpClient. If you use DefaultHttpClient without using those methods, you would get a warning message.
Here is an example of how to mock http response:
#RunWith(RobolectricTestRunner.class)
public class ApiTest {
#Test
public void test() {
Api api = new Api();
Robolectric.addPendingHttpResponse(200, "dummy");
String responseBody = api.get("www.example.com");
assertThat(responseBody, is("dummy"));
}
}
You can find more examples by looking at Robolectric's test codes.
I answered another version of this same question, but...
What you have here is not using anything from Android, so Robolectric is basically irrelevant. This is all standard Java and the Apache HTTP library. You simply need a mocking framework and dependency injection to simulate the HttpClient (see my other answer for links). It doesn't have network access while unit testing, and so it fails.
When testing classes that use parts of the Android framework, you can use Robolectric (or similar) to mock or simulate Android.jar since your unit testing framework isn't going to have access to that either.

Problem with accessing google tasks with client login

I'm trying to write application for Android to access Google Tasks. I decided to use ClientLogin authorization method.
I'm getting ClientLogin "Auth" marker from first POST request. Then i try to retrieve a user's task lists with GET request. I wrote the following code for this:
String requestString = "https://www.googleapis.com/tasks/v1/users/#me/lists";
String resultString = "";
try {
URLConnection connection1 = null;
URL url = new URL(requestString);
connection1 = url.openConnection( );
HttpURLConnection httpsConnection1 = (HttpURLConnection)connection1;
httpsConnection1.setRequestMethod("GET");
httpsConnection1.setRequestProperty("Authorization", "GoogleLogin auth="+authkeyString);
httpsConnection1.setDoInput(true);
httpsConnection1.connect();
int responseCode = httpsConnection1.getResponseCode();
System.out.println(responseCode);
if (responseCode == HttpsURLConnection.HTTP_OK) {
InputStream in = httpsConnection1.getInputStream();
InputStreamReader isr = new InputStreamReader(in, "UTF-8");
StringBuffer data = new StringBuffer();
int c;
while ((c = isr.read()) != -1){
data.append((char) c);
}
resultString = new String (data.toString());
}
else{
resultString = "Errror - connection problem";
}
}
httpsConnection1.disconnect();
}
catch (MalformedURLException e) {
resultString = "MalformedURLException1:" + e.getMessage();
}
catch (IOException e) {
resultString = "IOException1:" + e.getMessage();
}
Here is "authkeyString" - string variable with authorization marker.
When i run application under real Android device i receive: "IOException:SSL handshake failure: Failure is ssl library, usually a protocol error ..... "
Also i tried to run this code from simple java application from desktop:
Exception in thread "main" java.lang.IllegalArgumentException: Illegal character(s) in message header value: GoogleLogin auth=DQ ..... UT
at sun.net.www.protocol.http.HttpURLConnection.checkMessageHeader(HttpURLConnection.java:428)
at sun.net.www.protocol.http.HttpURLConnection.isExternalMessageHeaderAllowed(HttpURLConnection.java:394)
at sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(HttpURLConnection.java:2378)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestProperty(HttpsURLConnectionImpl.java:296)
at Tasks.main(Tasks.java:81)
ClientLogin with username / password
If you want to use ClientLogin with the Google APIs Client Library for Java , you'll need to setup a HttpRequestFactory that supports authentication.
private static HttpTransport transport = new ApacheHttpTransport();
public static HttpRequestFactory createRequestFactory(
final HttpTransport transport) {
return transport.createRequestFactory(new HttpRequestInitializer() {
public void initialize(HttpRequest request) {
GoogleHeaders headers = new GoogleHeaders();
headers.setApplicationName("MyApp/1.0");
request.headers=headers;
try {
authorizeTransport(request);
} catch (Exception e) {
e.printStackTrace();
}
}
});
Notice the authorizeTransport method, that will basically authorize the request. The authorizeTransport looks like this:
private void authorizeTransport(HttpRequest request) throws HttpResponseException, IOException {
// authenticate with ClientLogin
ClientLogin authenticator = new ClientLogin();
authenticator.authTokenType = Constants.AUTH_TOKEN_TYPE;
authenticator.username = Constants.USERNAME;
authenticator.password = Constants.PASSWORD;
authenticator.transport = transport;
try {
Response response = authenticator.authenticate();
request.headers.authorization=response.getAuthorizationHeaderValue();
} catch (HttpResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
You basically setup a ClientLogin authentication method by providing a username/passsword. The authenticate method will authenticate based on the provided values and returns a response object that can be added to the HTTP header to provide ClientLogin authentication.
Android AccountManager
In order to integrate with the Android AccountManager (avoiding the android user to type in his username / password) , you can find some sample code here http://code.google.com/p/google-api-java-client/wiki/AndroidAccountManager
The fact that the user doesn't need to key in his username/passwords adds to the users comfort level, but the solution remains relatively insecure.
I would strongly suggest doing the following :
Use a client library
I would suggest moving to Google APIs Client Library for Java for this type of interaction. It's Android compatible java client library for all kinds of Google APIs.
You don't want to be bothered with implementing low level HTTP, security and JSON plumbing.
The Google Task API Developers guide also mentions the same library. The library will take care of the authentication for you. If you want to use ClientLogin, all you'll have to do is specify a username/password, or integrate with the Android AccountManager.
Avoid using ClientLogin
ClientLogin is considered insecure, and a number of security holes have been found regarding this authentication mechanism. Google also doesn't recommend it. However, should you decide to continue using ClientLogin, the Google APIs Client Library for Java does support it.

Categories

Resources