I am making a login app to retreive some information from the link that appears in the code. My problem is that I'm getting a "400 Bad request. Your browser sent a request that this server could not understand. [...] Server at idp.tut.fi Port 443" in the Log file.
Besides, that link handles RC4_128 with SHA1 for authentication and RSA for key exchange but don't really know where I can apply those protocols in my code.
Thanks for your help!
This is my code:
public class POPLogin extends Activity {
private EditText usr, pass;
private Button submitButton;
private CharSequence notify;
private String res, resp;
private final String link = "https://idp.tut.fi/idp/Authn/UserPassword";
private URL url;
public static boolean isNetworkAvailable(Context context) {
return ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo() != null;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_poplogin);
usr = ((EditText) findViewById(R.id.usernameField));
pass = ((EditText) findViewById(R.id.passwordField));
submitButton = (Button) findViewById(R.id.submitButton);
submitButton.getBackground().setColorFilter(new LightingColorFilter(0x00FFB90F, 0xFFAA0000));
/*
* This method controls the login button so that the correct
* information is sent to the server.
*/
submitButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(isNetworkAvailable(getApplicationContext())) { // If there is an Internet connection available
/*
* A new thread is created from the main one
* to separate the login process (AsyncTask, https operations).
*/
new Thread(new Runnable() {
public void run() {
try {
url = new URL(link);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// Create the SSL Connection
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
// SSL Authentication
String userpass = usr.getText().toString() + ":" + pass.getText().toString();
String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
conn.setRequestProperty("Authorization", basicAuth);
Log.i("NOTIFICATION", "All SSL parameters set");
// Set timeout and method
conn.setReadTimeout(7000);
conn.setConnectTimeout(7000);
conn.setRequestMethod("POST");
conn.setDoInput(true); // Flag indicating this connection is used for output (POST)
conn.connect();
Log.i("NOTIFICATION", "Connection request sent");
// Check HTTP Response Code
int status = conn.getResponseCode();
InputStream is;
if (status >= 400 ) {
is = conn.getErrorStream();
} else {
is = conn.getInputStream();
}
Log.i("NOTIFICATION", "HTTP Code Checked");
// Receives the answer
resp = null;
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
while((res = rd.readLine()) != null) {
resp += res;
}
Log.i("NOTIFICATION", "Answer received");
Log.i("CODE", resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} else {
notify = "Internet Connection not available";
}
if(notify != null) {
Toast toast = Toast.makeText(getApplicationContext(), notify, Toast.LENGTH_SHORT);
toast.show();
notify = null;
}
}
});
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.poplogin, menu);
return true;
}
}
If you got an HTTP error code it is proof that your HTTPS and therefore SSL setup is working perfectly.
The problem is in the data you're sending. It looks like you need to use a java.net.Authenticator rather than try to do it by hand.
Related
I can't figure out what is up with this code. First of all, as it is here, it works. But I'm afraid I have missed an important concept and I don't want it to come back and bite me later. My code below will write a blank line to a text log that I have created for testing purposes if I don't add the line "connection.getResponseMessage.' It will also work with 'getResponseCode.' Why?
Why does it write an empty buffer to the OutputStream without these codes?
public class AdminActivity extends AppCompatActivity {
Context mContext;
private static final String TAG = "AdminActivity";
EditText mSystemID, mSystemPassword;
RecyclerView mRecyclerView;
Button mUpdateButton, mDownloadButton;
FileItemAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
mContext = this;
mSystemID = findViewById(R.id.et_system_id);
mSystemPassword = findViewById(R.id.et_system_password);
mRecyclerView = findViewById(R.id.rv_file_names);
mUpdateButton = findViewById(R.id.bt_update_files_list);
mDownloadButton = findViewById(R.id.bt_download_file);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
DividerItemDecoration divider = new DividerItemDecoration(mContext, layoutManager.getOrientation());
divider.setDrawable(ContextCompat.getDrawable(mContext, R.drawable.divider_dark));
// TESTING TESTING TESTING TESTING TESTING //
mUpdateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new SendInfoToServer().execute("A new Test");
}
});
}
private static class SendInfoToServer extends AsyncTask<String, String, String> {
HttpURLConnection connection = null; //***** Should eventually change to https instead of http
OutputStream out = null;
#Override
protected String doInBackground(String... params) {
String parameters = params[0];
try {
URL url = new URL("http://www.example.com/login/webhook.php");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.connect();
out = new DataOutputStream(connection.getOutputStream());
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
writer.write(parameters);
writer.flush();
writer.close();
Log.d(TAG, "response message: " + connection.getResponseMessage());
} catch (IOException e) {
Log.d(TAG, "an error occured");
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
}
}
I've tried to ask this question multiple different ways and nobody has given me any useful input. This, I guess, is my last attempt to simplify the question. Above is the entire Activity. It has already been suggested to remove 'writer.close()' but that didn't work.
Thanks in advance
HttpURLConnection has a terrible API and is very confusing to use. I would strongly recommend using OkHttp in its place. With OkHttp, you would make the request with the following code:
String parameters = params[0];
Response response;
try {
MediaType contentType = MediaType.parse("text/plain; charset=utf-8");
RequestBody body = RequestBody.create(contentType, parameters);
Request request = new Request.Builder()
.url("http://www.example.com/login/webhook.php")
.post(body)
.build();
response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
}
} catch (IOException e) {
Log.d(TAG, "an error occured");
e.printStackTrace();
} finally {
if(response != null) {
response.close();
}
}
return null;
If you want to stick with HttpURLConnection, this answer explains the connection process pretty well.
In my app, I am using broadcast receiver to capture the internet connect and disconnect state. Its working fine. Here is the code:
public class CheckConnectivity extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent arg1) {
boolean isNotConnected = arg1.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if(isNotConnected){
Toast.makeText(context, "Disconnected", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(context, "Connected", Toast.LENGTH_LONG).show();
}
}
}
I am using http web services in my app. I wrote them in different class.
HttpConnect.java:
public class HttpConnect {
public static String finalResponse;
public static HttpURLConnection con = null;
public static String sendGet(String url) {
try {
StringBuffer response = null;
//String urlEncode = URLEncoder.encode(url, "UTF-8");
URL obj = new URL(url);
Log.e("url", obj.toString());
con = (HttpURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
//add request header
con.setConnectTimeout(10000);
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
finalResponse = response.toString();
} catch (IOException e) {
e.printStackTrace();
}
//print result
return finalResponse;
}
}
My problem is, how to disconnect or cancel http request when broadcast receiver says no connectivity.
I have tried this code below:
if(isNotConnected){
Toast.makeText(context, "Disconnected", Toast.LENGTH_LONG).show();
if(HttpConnect.con != null)
{
HttpConnect.con.disconnect();
}
}
But its not working. Can anybody tell me how to cancel http request when broadcast receiver captures lost connection?
You should create one method like as below:
public static boolean isOnline(Context mContext) {
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
And before your http call, you should just check, if it returns true, it means internet is available and if it is false, it means internet not available and you can stop your http call.
Also, if your call is already initiated, you should set request timeout value there like 30 seconds, if there is no internet, you will get exception of TimeoutError
I'm currently using twitter fabric framework and trying to retrieve the list of my own account tweets. I tried searching online to no avail. The example in the document shows how to display a tweet based on tweetID. I do not want that. I do understand that REST client makes a http connection with the supplied variables and to retrieve the JSON results back to parse and etc.
This are my current codes which upon successful login it will display another activity which i want my tweets to be shown here.
public void success(Result<TwitterSession> result) {
// Do something with result, which provides a TwitterSession for making API calls
TwitterSession session = Twitter.getSessionManager().getActiveSession();
TwitterAuthToken authToken = session.getAuthToken();
token = authToken.token;
secret = authToken.secret;
Log.i("token",token);
Log.i("secret",secret);
successNewPage();
}
I have also passed the token and secret key over to the next activity using intent
public void successNewPage(){
Intent intent = new Intent(this, LoginSuccess.class);
intent.putExtra("token",token);
intent.putExtra("secret", secret);
startActivity(intent);
}
On the new activity class, i followed their documentation and came out with this,
TwitterAuthConfig authConfig = new TwitterAuthConfig("consumerKey", "consumerSecret");
Fabric.with(this, new TwitterCore(authConfig), new TweetUi());
TwitterCore.getInstance().logInGuest(new Callback() {
public void success(Result appSessionResult) {
//Do the rest API HERE
Bundle extras = getIntent().getExtras();
String bearerToken = extras.getString("token");
try {
fetchTimelineTweet(bearerToken);
} catch (IOException e) {
e.printStackTrace();
}
}
public void failure(TwitterException e) {
Toast.makeText(getApplicationContext(), "Failure =)",
Toast.LENGTH_LONG).show();
}
});
}
And the retrieve of tweets would be:
// Fetches the first tweet from a given user's timeline
private static String fetchTimelineTweet(String endPointUrl)
throws IOException {
HttpsURLConnection connection = null;
try {
URL url = new URL(endPointUrl);
connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setRequestProperty("Host", "api.twitter.com");
connection.setRequestProperty("User-Agent", "anyApplication");
connection.setRequestProperty("Authorization", "Bearer " + endPointUrl);
connection.setUseCaches(false);
String res = readResponse(connection);
Log.i("Response", res);
return new String();
} catch (MalformedURLException e) {
throw new IOException("Invalid endpoint URL specified.", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
What i get in my log is:
380-380/com.example.john.fabric W/System.errīš java.io.IOException: Invalid endpoint URL specified.
Is my url wrong? Or is the token which I set in the endpointURL wrong too?
Any advice would be greatly appreciated. Thanks!
That should be the case, the message was thrown by the fetchTimelineTweet function. That should be caused by this line : URL url = new URL(endPointUrl); which tells that the endPointUrl causes MalformedURLException
EDIT :
According to the Twitter Dev Page, you should put this as endpointURL : https://dev.twitter.com/rest/reference/get/statuses/user_timeline and pass the user screenname as parameter.
EDIT 2 :
I think your code should be like this :
private static String fetchTimelineTweet(String endPointUrl, String token) // this line
throws IOException {
HttpsURLConnection connection = null;
try {
URL url = new URL(endPointUrl);
connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setRequestProperty("Host", "api.twitter.com");
connection.setRequestProperty("User-Agent", "anyApplication");
connection.setRequestProperty("Authorization", "Bearer " + token); // this line
connection.setUseCaches(false);
String res = readResponse(connection);
Log.i("Response", res);
return new String();
} catch (MalformedURLException e) {
throw new IOException("Invalid endpoint URL specified.", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
I am making a login app to retreive some information from the link that appears in the code. My problem is that I'm getting a "400 Bad request. The request could not be understood by server due to malformed syntax" in the Log file.
Besides, that link handles RC4_128 with SHA1 for authentication and RSA for key exchange but don't really know where I can apply those protocols in my code.
Thanks for your help!
This is my code:
public class POPLogin extends Activity {
private EditText usr, pass;
private Button submitButton;
private CharSequence notify;
private String res, resp;
private final String link = "https://pop-portal.tut.fi/portal/page/portal/POP-portaali/20Opinnot/22Omat%20suoritukset";
private URL url;
public static boolean isNetworkAvailable(Context context) {
return ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo() != null;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_poplogin);
usr = ((EditText) findViewById(R.id.usernameField));
pass = ((EditText) findViewById(R.id.passwordField));
submitButton = (Button) findViewById(R.id.submitButton);
submitButton.getBackground().setColorFilter(new LightingColorFilter(0x00FFB90F, 0xFFAA0000));
/*
* This method controls the login button so that the correct
* information is sent to the server.
*/
submitButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(isNetworkAvailable(getApplicationContext())) { // If there is an Internet connection available
/*
* A new thread is created from the main one
* to separate the login process (AsyncTask, https operations).
*/
new Thread(new Runnable() {
public void run() {
try {
url = new URL(link);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// Create the SSL Connection
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
// SSL Authentication
String userpass = usr.getText().toString() + ":" + pass.getText().toString();
String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
conn.setRequestProperty("Authorization", basicAuth);
Log.i("NOTIFICATION", "All SSL parameters set");
// Set timeout and method
conn.setReadTimeout(7000);
conn.setConnectTimeout(7000);
conn.setRequestMethod("POST");
conn.setDoInput(true); // Flag indicating this connection is used for output (POST)
conn.connect();
Log.i("NOTIFICATION", "Connection request sent");
// Check HTTP Response Code
int status = conn.getResponseCode();
InputStream is;
if (status >= 400 ) {
is = conn.getErrorStream();
} else {
is = conn.getInputStream();
}
Log.i("NOTIFICATION", "HTTP Code Checked");
// Receives the answer
resp = null;
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
while((res = rd.readLine()) != null) {
resp += res;
}
Log.i("NOTIFICATION", "Answer received");
Log.i("CODE", resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} else {
notify = "Internet Connection not available";
}
if(notify != null) {
Toast toast = Toast.makeText(getApplicationContext(), notify, Toast.LENGTH_SHORT);
toast.show();
notify = null;
}
}
});
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.poplogin, menu);
return true;
}
}
I am searching about how to send notification using C2DM. I found something and using that I am able to generate Registration Key as well as an Authentication Key.
But after that in ServerSimulator class (sever side code) I got 401 Error (401 Unauthorized).Now I passed Username and Password manually, which I synchronized in my Android device. I get same error as before.
I face this problem when I click on send message button..
I am stuck on this query. Has anyone managed to do this?
public class ServerSimulator extends Activity
{
private SharedPreferences prefManager;
private final static String AUTH = "authentication";
private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
public static final String PARAM_REGISTRATION_ID = "registration_id";
public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
public static final String PARAM_COLLAPSE_KEY = "collapse_key";
private static final String UTF8 = "UTF-8";
// Registration is currently hardcoded
private final static String YOUR_REGISTRATION_STRING = "APA91bFkxmtIj5XiBU-Cze64s0gXNb7OmiWWZg-qLKibpLsVXaWq1X7hoRV9Ld9COYXirZAgkYegZBdBfUGt3lgtuhNJopvHB0KJ5ZyJ6Kt_HYRrZhgdJ1Y";
private SharedPreferences prefs;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
prefManager = PreferenceManager.getDefaultSharedPreferences(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.mymenu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuitem_user:
Intent intent = new Intent(this, UserPreferences.class);
startActivity(intent);
break;
default:
break;
}
return false;
}
public void getAuthentification(View view) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(this);
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(
"https://www.google.com/accounts/ClientLogin");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("Email","myEmail id")));
nameValuePairs.add(new BasicNameValuePair("Passwd","my password")));
nameValuePairs.add(new BasicNameValuePair("accountType", "GOOGLE"));
nameValuePairs.add(new BasicNameValuePair("source","Google-cURL-Example"));
nameValuePairs.add(new BasicNameValuePair("service", "ac2dm"));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
Log.e("HttpResponse", line);
if (line.startsWith("Auth=")) {
Editor edit = prefManager.edit();
edit.putString(AUTH, line.substring(5));
edit.commit();
String s = prefManager.getString(AUTH, "n/a");
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void showAuthentification(View view) {
String s = prefManager.getString(AUTH, "n/a");
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
public void sendMessage(View view) {
try {
Log.e("Tag", "Started");
String auth_key = prefManager.getString(AUTH, "n/a");
// Send a sync message to this Android device.
StringBuilder postDataBuilder = new StringBuilder();
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
.append(YOUR_REGISTRATION_STRING);
// if (delayWhileIdle) {
// postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE)
// .append("=1");
// }
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
.append("0");
postDataBuilder.append("&").append("data.payload").append("=")
.append(URLEncoder.encode("Lars war hier", UTF8));
byte[] postData = postDataBuilder.toString().getBytes(UTF8);
// Hit the dm URL.
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",
Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="
+ auth_key);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int responseCode = conn.getResponseCode();
Log.e("Tag", String.valueOf(responseCode));
// Validate the response code
if (responseCode == 401 || responseCode == 403) {
// The token is too old - return false to retry later, will
// fetch the token
// from DB. This happens if the password is changed or token
// expires. Either admin
// is updating the token, or Update-Client-Auth was received by
// another server,
// and next retry will get the good one from database.
Log.e("C2DM", "Unauthorized - need token");
}
// Check for updated token header
String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) {
Log.i("C2DM",
"Got updated auth token from datamessaging servers: "
+ updatedAuthToken);
Editor edit = prefManager.edit();
edit.putString(AUTH, updatedAuthToken);
}
String responseLine = new BufferedReader(new InputStreamReader(
conn.getInputStream())).readLine();
// NOTE: You *MUST* use exponential backoff if you receive a 503
// response code.
// Since App Engine's task queue mechanism automatically does this
// for tasks that
// return non-success error codes, this is not explicitly
// implemented here.
// If we weren't using App Engine, we'd need to manually implement
// this.
if (responseLine == null || responseLine.equals("")) {
Log.i("C2DM", "Got " + responseCode
+ " response from Google AC2DM endpoint.");
throw new IOException(
"Got empty response from Google AC2DM endpoint.");
}
String[] responseParts = responseLine.split("=", 2);
if (responseParts.length != 2) {
Log.e("C2DM", "Invalid message from google: " + responseCode
+ " " + responseLine);
throw new IOException("Invalid response from Google "
+ responseCode + " " + responseLine);
}
if (responseParts[0].equals("id")) {
Log.i("Tag", "Successfully sent data message to device: "
+ responseLine);
}
if (responseParts[0].equals("Error")) {
String err = responseParts[1];
Log.w("C2DM",
"Got error response from Google datamessaging endpoint: "
+ err);
// No retry.
throw new IOException(err);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
You are currently implementing C2DM in an older way. The way you are doing offers a lot of customizability, but not many people need that kind of customizability. With the new Google Plugin 2.4 Beta they have actually started integrating it all in, and it's pretty nice.
I'd highly recommend you watch the Google IO Android + AppEngine. They show how to integrate Android, AppEngine, and C2DM together really really simply. You can create something they call an "AppEngine Connected Android Project". So instead of making a ServerSimulator, you'd be actually working with a real server that can all be setup for free.
http://www.youtube.com/watch?v=M7SxNNC429U
If you wanted to move to another server, you'd have to re-write the server-side code, and then just change the URL that it's posting to. Pretty simple. I'd highly recommend checking out this example and working with the stock code, as it gives you something working right off the bat to play with:
FYI, there is currently a bug in the code (as it is in beta atm) when it comes to registering to a real hosted appengine server (everything works fine locally). It tries to send an expired registration token. I've been in contact with the google developers and they provided a fix for me. Let me know if you get to the point where you need it.