I am working at the REST API for a new Social Network Android App at the moment using Spring Android for the Client and Spring Boot for the Server.
I am having trouble securing the Server using Spring Security, because i don't understand how to use it properly. After reading tons of sample apps i gave up on spring security and found this tutorial on how to secure APIs using Jersey.
Instead of javascript i am using the Jersey Client API to test the implementation
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/demo-business-resource/login");
Invocation.Builder invoBuilder = target.request();
invoBuilder.header("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("username", "username2");
formData.add( "password", "passwordForUser2");
Response response = invoBuilder.post(Entity.form(formData));
System.out.println(response);
response.getEntity();
The POST request is successful, but i cant get the JSON object which should be the Entity of the Response. response.getEntity(); returns a HttpUrlConnector Object.
Here the related Server Code
#POST
#Path( "login" )
#Produces( MediaType.APPLICATION_JSON )
public Response login(
#Context HttpHeaders httpHeaders,
#FormParam( "username" ) String username,
#FormParam( "password" ) String password ) {
DemoAuthenticator demoAuthenticator = DemoAuthenticator.getInstance();
String serviceKey = httpHeaders.getHeaderString( DemoHTTPHeaderNames.SERVICE_KEY );
try {
String authToken = demoAuthenticator.login( serviceKey, username, password );
JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();
jsonObjBuilder.add( "auth_token", authToken );
JsonObject jsonObj = jsonObjBuilder.build();
return getNoCacheResponseBuilder( Response.Status.OK ).entity( jsonObj.toString() ).build();
} catch ( final LoginException ex ) {
JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();
jsonObjBuilder.add( "message", "Problem matching service key, username and password" );
JsonObject jsonObj = jsonObjBuilder.build();
return getNoCacheResponseBuilder( Response.Status.UNAUTHORIZED ).entity( jsonObj.toString() ).build();
}
}
private Response.ResponseBuilder getNoCacheResponseBuilder( Response.Status status ) {
CacheControl cc = new CacheControl();
cc.setNoCache( true );
cc.setMaxAge( -1 );
cc.setMustRevalidate( true );
return Response.status( status ).cacheControl( cc );
}
I am new to Jersey and i only want to use it to generate the Authentication Token, because i get 404 Not Found errors using Spring. (I am working with spring-jersery )
Here my Spring approach of the client
RestTemplate template = new RestTemplate();
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
MultiValueMap<String,String> formData=new LinkedMultiValueMap<String,String>();
formData.add("username", "username2");
formData.add( "password", "passwordForUser2");
Model_LoginProfile log = new Model_LoginProfile();
log.setLoginName("username2");
log.setPassword("passwordForUser2");
HttpHeaders requestHeaders=new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.set("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
HttpEntity<Model_LoginProfile> requestEntity = new HttpEntity<Model_LoginProfile>(log, requestHeaders);
ResponseEntity<String> result = template.postForEntity("http://localhost:8080/demo-business-resource/login", requestEntity, String.class);
}
Maybe someone has a fix for that as well. :)
Thanks in advance
Related
enter image description hereI have created REST API in ASP.NET with http://server/token as URL.
The header having
content-type: application/x-www-form-urlencode
The body have grant_type as password, username and password will get json data with token.
For further data access token can be used above method works with postman
I need to implement a client in Android Studio or Xamarin.
as urls in postman is "example.com/token"; , then in Header Key value pais for content type as ("Content-Type:application/x-www-form-urlencoded) and in body key value pair as (grant_type:password, username:email,password:pass) and after send the response is in json format as follows { "access_token": "token", "token_type": "bearer", "expires_in": 1209599, "userName": "mail#gmail.com", ".issued": "Fri, 09 Dec 2016 19:19:18 GMT", ".expires": "Fri, 23 Dec 2016 19:19:18 GMT" }
this same needed to be done in android
Include in your dependencies System.Net.Http (requires Xamarin profile 111) and then you can use that to create a HttpClient and request the token via HTTP POST (akin to what you were doing in Postman) like this..
_client = new HttpClient();
var uri = new Uri("http://server/token");
var content = new FormUrlEncodedContent(
new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("username", _username),
new KeyValuePair<string, string>("password", _password),
new KeyValuePair<string, string>("grant_type", "password")
});
HttpResponseMessage response = await _client.PostAsync(uri, content);
Where _username and _password are strings.
Then read the response out by converting it into a Dictionary or any other reasonable alternative approach to parsing the JSON response.
if (response.StatusCode == HttpStatusCode.OK) {
var jsonContent = await response.Content.ReadAsStringAsync();
var responseDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonContent);
if (responseDict.ContainsKey("access_token"))
_token = responseDict["access_token"];
}
Then once you have the token, you can include it as a default authorization value for all headers from that HttpClient instance!
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);
Where _token is the token as it's encoded string, e.g. "eyJ0eXAiOiJKV1QiLC..."
Just implemented this and to verify it's correctness - I ran it against a production environment I have set up to verify using JWTs and it worked a charm.
this works, it looks ugly but you can change it
var authCredentials = "grant_type=password&username=" + WebUtility.UrlEncode(LoginBindingModel.Email) + "&password=" + LoginBindingModel.Password;
string response = await Client.MakePostFormRequest("token", authCredentials);
public static async Task<string> MakePostFormRequest(string url, string data)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(BaseUrl + "token");
// Set the Method property of the request to POST.
request.Accept = "*/*";
request.Method = "POST";
// Create POST data and convert it to a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(data);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
//request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = await request.GetRequestStreamAsync().ConfigureAwait(false);
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Dispose();
// Get the response.
WebResponse response = await request.GetResponseAsync().ConfigureAwait(false);
// Display the status.
//Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
//Console.WriteLine(responseFromServer);
// Clean up the streams.
TokenViewModel TokenViewModel = JsonConvert.DeserializeObject<TokenViewModel >(responseFromServer);
VariablesGlobales.Token = TokenViewModel.access_token;
VariablesGlobales.LoginStamp = TokenViewModel.LoginStamp;
reader.Dispose();
dataStream.Dispose();
response.Dispose();
return responseFromServer;
}
catch (Exception ex)
{
return "";
}
}
And when you want to authenticate your request
public static async Task<string> MakePostRequest(string url, string data)
{
var result = "";
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(BaseUrl + url);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
if (VariablesGlobales.Token != "")
{
httpWebRequest.Headers[HttpRequestHeader.Authorization] = "Bearer " + VariablesGlobales.Token;
}
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)))
{
streamWriter.Write(data);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)(await httpWebRequest.GetResponseAsync().ConfigureAwait(false));
if (httpResponse.StatusCode.ToString() == "OK")
{
result = httpResponse.StatusCode.ToString();
}
else
{
result = "";
}
}
catch (Exception ex)
{
result = "";
}
return result;
}
}
I'm trying to convert my Android post request to iOS (Swift). Currently, this is the Android code:
JSONObject json = new JSONObject();
json.put("major", Major);
json.put("minor", Minor);
json.put("uuid", UUID);
json.put("userid", id);
int TIMEOUT_MILLISEC = 10000; // = 10 seconds
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT_MILLISEC);
HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT_MILLISEC);
HttpClient client = new DefaultHttpClient(httpParams);
HttpPost request = new HttpPost("http://" + ipAddress + ":8080/");
request.setHeader("Content-Type", "application/json");
request.setEntity(new ByteArrayEntity(
json.toString().getBytes("UTF8")));
HttpResponse response = client.execute(request);
This works perfectly fine.
However, when I try to convert it to Swift, the server doesn't receive anything even though I know that it's executing the request.
Swift:
var request = NSMutableURLRequest(URL: NSURL(string: URLString)!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["major": "1", "minor": "2", "uuid": "00000000-1111-2222-3333-444444444444", "userid": "3"] as Dictionary<String, String>
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let task = session.dataTaskWithRequest(request) { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
let success = json["success"] as? Int
} else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
}
} catch let parseError {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
}
}
Any help or direction would be nice. Thanks.
Edit 1: A task.resume() got me a response from the server. However, if anyone knows how to convert "request.setEntity(new ByteArrayEntity(json.toString().getBytes("UTF8")));" in Swift, that would be really helpful.
#Naga Krishnamraju
For your second concern where need to parse json string to object you can do that using following way
if(response != nil)
{
// Print out reponse body
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
//print("****** response data = \(responseString!)")
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
print(json ?? "Error")
print("responseString :-%#",responseString ?? "error");
DispatchQueue.main.async {
if((json?.count)! > 0)
{
//here you get json as dictionary now you can have your implementation
}
}
}catch
{
print(error)
failure(error as NSError);
}
}
Did you forget to add task.resume ?
task.resume() after block will do the job
I am asking this question based on the answers in this link
POST request via RestTemplate in JSON
I actually wanted to send JSON from client and receive the same at REST server. Since the client part is done in the link I mentioned above. For the same how would I handle that request at server end.
CLIENT:
// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
.exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
}
SERVER:
#RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(#RequestBody HttpEntity<String> entity) {
JSONObject jsonObject = new JSONObject(entity.getBody());
String username = jsonObject.getString("username");
return new ResponseEntity<>(username, HttpStatus.OK);
}
This gives me 400 bad request error at client side. Hoping for some clues about how to handle this at server side.
HTTPEntity should not be used in your server method. Instead use the argument which is being passed to HTTPEntity from your client. In your case it has to String since you are passing string from client. Below code should work for you.
#RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(#RequestBody String jsonStr) {
System.out.println("jsonStr " + jsonStr);
JSONObject jsonObject = new JSONObject(jsonStr);
String username = jsonObject.getString("username");
return new ResponseEntity<String>(username, HttpStatus.OK);
}
My advice is to create bean class and use it in server and client instead of converting it to String. It will improve readability of the code.
When using the Spring RestTemplate, I usually prefer to exchange objects directly. For example:
Step 1: Declare and define a data holder class
class User {
private String username;
private String password;
... accessor methods, constructors, etc. ...
}
Step 2: Send objects of this class to the server using RestTemplate
... You have a RestTemplate instance to send data to the server ...
// You have an object to send to the server, such as:
User user = new User("user", "secret");
// Set HTTP headers for an error-free exchange with the server.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Generate an HTTP request payload.
HttpEntity<User> request = new HttpEntity<User>(user, headers);
// Send the payload to the server.
restTemplate.exchange("[url]", [HttpMethod], request, User.class);
Step 3: Configure a ContentNegotiatingViewResolver on the server
Declare a bean of the type ContentNegotiatingViewResolver in the Spring XML or Java configuration. This will help the server automatically bind HTTP requests with bean objects.
Step 4: Receive the request on the server
#RestController
#RequestMapping("/user")
class UserAPI {
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public User create(User user) {
// Process the user.
// Possibly return the same user, although anything can be returned.
return user;
}
}
The ContentNegotiatingViewResolver ensures that the incoming request gets translated into a User instance without any other intervention.
Step 5: Receive the response on the client
// Receive the response.
HttpEntity<User> response = restTemplate.exchange("[url]", [HttpMethod], request, User.class);
// Unwrap the object from the response.
user = response.getBody();
You will notice that the client and the server both use the same bean class (User). This keeps both in sync as any breaking change in the bean structure would immediately cause a compilation failure for one or both, necessitating a fix before the code is deployed.
Getting connected from an Android app to Toodledo API v3 works.
So, I know that I have a valid access_token (and refresh token).
GET requests work.
How can I add a folder ... using a POST request?
The code is below ... it keeps on spinning for new access tokens.
HttpResponse response = null;
JSONObject folderJS;
try {
Credential cred = flow.loadCredential( userId);
String apiCallUrl = "https://api.toodledo.com/3/folders/add.php";
GenericData data = new GenericData();
data.put( "name", folderName);
data.put( "private", "1");
// data.put( "access_token", accessToken); <== this is wrong
JsonHttpContent httpContent = new JsonHttpContent(new JacksonFactory(), data);
response = HTTP_TRANSPORT.createRequestFactory( cred).buildPostRequest(
new GenericUrl( apiCallUrl), httpContent).execute();
The problem was:
data.put( "access_token", accessToken);
When you add this line you get errors in processing the request. So, user error.
I need to upload some data on a site, using a POST request. I know to use HTTP client to execute a POST request
The problem is that in order to do this, you should authenticate first.
The site is a simple page prompting for a username and a password. I assume it stores a cookie in the browser and checks subsequent requests to see if I'm already authenticated.
But I don't have a concrete idea how to implement this on Android.
The client just gave me this:
URL to upload: http://xyz.com/?page=add
Credentials: admin/admin
Format of data:
$_POST = {
["Name"]=>string(255)
["Address"]=>string(255)
["ZIP"]=>string(50)
["City"]=>string(100)
["Phone"]=>string(50)
["Email"]=>string(50)
["Age"]=>int(11)
["Validation_Result"]=>string(255)
["Comment"]=>string(-)
}
$_FILES["Image"] = {
["name"]=>string "3D-graphics_3D_Triangles_006790_.jpg"
["type"]=>string "image/jpeg"
["tmp_name"]=>string "C:\Windows\Temp\php1362.tmp"
["error"]=>int(0)
["size"]=>int
}
And nothing else.
Could you please point me in the right direction how I would go about doing this?
How to do HTTP authentication in android?
Check out the top answer on this question. Very good explanation.
If you are doing the POST using HttpClient as the post you linked describes, you can add Basic Authentication by doing the following:
String username, password;
DefaultHttpClient client = new DefaultHttpClient();
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
client.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
HTH
I know this is a very old question, but this was the top search result I kept running into and I wanted to add another way that I managed to do this using CookieStore and HttpClient.
For my use case (Tomcat server configuration), I was hitting my base authenticated URL to get the cookie, POSTing my auth data to the form submission endpoint, and then using the cookie for subsequent calls. Here's the simplified piece of code that got it working for me:
String cookieUrl = "SOME_URL_THAT_WILL_PROVIDE_COOKIE";
String authenticateUrl = "URL_TO_POST_FORM_DATA";
String dataUrl = "AUTHENTICATED_URL_YOU_WANT_DATA_FROM";
final String userNameKey = "FORM_KEY_FOR_USERNAME";
final String userPassKey = "FORM_KEY_FOR_PASSWORD";
final String userName = "USER_NAME";
final String userPass = "USER_PASSWORD";
HttpClient client = new DefaultHttpClient();
CookieStore cookieStore = new BasicCookieStore();
HttpContext context = new BasicHttpContext();
context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
String getUrl = cookieUrl;
HttpGet get = new HttpGet( getUrl );
HttpResponse getResponse = client.execute(get, context);
Log.d( "ConnectionTest", "GET # " + getUrl );
Log.d( "ConnectionTest", getResponse.getStatusLine().toString() );
List<NameValuePair> authDataList = new ArrayList<NameValuePair>();
authDataList.add( new NameValuePair() {
#Override
public String getName() {
return userNameKey;
}
#Override
public String getValue() {
return userName;
}
} );
authDataList.add( new NameValuePair() {
#Override
public String getName() {
return userPassKey;
}
#Override
public String getValue() {
return userPass;
}
} );
HttpEntity authEntity = new UrlEncodedFormEntity( authDataList );
String authPostUrl = authenticateUrl;
HttpPost authPost = new HttpPost( authPostUrl );
authPost.setEntity( authEntity );
HttpResponse authPostResponse = client.execute(authPost, context);
Log.d( "ConnectionTest", "POST # " + authPostUrl );
Log.d( "ConnectionTest", authPostResponse.getStatusLine().toString() );
String getUsersUrl = dataUrl;
HttpGet usersGet = new HttpGet( getUsersUrl );
HttpResponse usersGetResponse = client.execute(usersGet, context);
Log.d( "ConnectionTest", "GET # " + getUsersUrl );
Log.d( "ConnectionTest", usersGetResponse.getStatusLine().toString() );
Log.d( "ConnectionTest", EntityUtils.toString( usersGetResponse.getEntity() ) );