I'm trying to perform an authentication from an android app. I'm basically sending the username and password(not encoded) to my rest api endpoint which is : /api/management/login I'm using Retrofit). After that, I check if the user exists or not and return the object if it does or null if it does not.I noticed that the encoded password is different from the one stored in my database even if the initial password strings are the same. I read that PasswordEncoder interface is generating a random salt in order to encode the password. Is there a way to make salt unique ?
Here is my spring security configuration file :
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private UserPrincipalDetailsService userPrincipalDetailsService;
public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService) {
this.userPrincipalDetailsService = userPrincipalDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {}).and()
.authenticationProvider(authenticationProvider())
.authorizeRequests()
.antMatchers("/management/*").hasRole("ADMIN")
.antMatchers("/*").hasRole("ADMIN")
.antMatchers("/management/professor*").hasRole("ADMIN")
.antMatchers("/management/absence*").hasRole("ADMIN")
.antMatchers("/management/room*").hasRole("ADMIN")
.anyRequest().permitAll()
.and()
.formLogin()
.loginProcessingUrl("/signin").permitAll()
.loginPage("/login").permitAll()
.successHandler(mySimpleUrlAuthenticationHandler())
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
.and()
.rememberMe().userDetailsService(userPrincipalDetailsService).rememberMeParameter("checkRememberMe");
}
#Bean
DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);
return daoAuthenticationProvider;
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
MySimpleUrlAuthenticationHandler mySimpleUrlAuthenticationHandler() {
return new MySimpleUrlAuthenticationHandler();
}
}
any recommendations ?
I think you're encoding the password that you received from the client and hard-coding that into SQL query with login id. If my assumption is correct, don't do that.
As you said
I check if the user exists or not and return the object if it does or null if it does not
Do not encode password and concatenate it to SQL query (in /login API). Instead, retrieve the data only based on login id. If it returns an object, then obviously it returns an encoded password. Now you need to compare already enoded passwords with the plain password received from the client.
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
BCryptPasswordEncoder encoded = BCryptPasswordEncoder();
boolean matches = encoder.matches("plain password from client", "encoded password here");
if (matches) {
// successull login
} else {
// invalid login credentials
}
For more refer to this BCryptPasswordEncoder#matches() SpringBoot doc
Hi I've been trying to set up a simple Android app to send a query to a GraphQL server I set up on my localhost via Springboot. If I don't use the app to send a request, either through GraphiQL or Postman, everything is fine and I have absolutely no issues. It's only when I send the request in the app through an Apollo Client that I get a 422 error.
I've set up log statements in Springboot that hosts the GraphQL server to log the payload.
Here's the schema as defined in Springboot.
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
Here's the query as defined in AndroidStudio for the Apollo Client to work with.
query BookById($id : ID) {
bookById(id : $id){
name
author{
firstName
lastName
}
}}
Here's the code in Android Studio.
public class MainActivity extends AppCompatActivity {
private static final String BASE_URL = "http://xxx.xxx.xxx.xxx:8080/graphql";
private static final String TAG = "MainActivity";
private TextView textBox;
private Button queryButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textBox = (TextView) findViewById(R.id.plainbox);
queryButton = (Button) findViewById(R.id.queryButton);
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
ApolloClient apolloClient = ApolloClient.builder()
.serverUrl(BASE_URL)
.okHttpClient(okHttpClient)
.build();
// To make requests to our GraphQL API we must use an instance
// of a query or mutation class generated by Apollo.
Input<String> id = Input.fromNullable("book-1");
BookByIdQuery bq = BookByIdQuery.builder()
.id("book-1")
.build();
queryButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "REGISTERED CLICK");
Log.d(TAG, "Book Query: " + bq.queryDocument());
apolloClient.query(bq).enqueue(new
ApolloCall.Callback<BookByIdQuery.Data>() {
#Override
public void onResponse(#NotNull com.apollographql.apollo.api.Response<BookByIdQuery.Data> dataResponse){
Log.d(TAG, "Got Response: \n" + dataResponse.toString());
// changing UI must be on UI thread
textBox.setText(dataResponse.data().toString());
}
#Override
public void onFailure(#NotNull ApolloException a){
Log.d(TAG, "Failed, ApolloException " + a);
}
}); // end apolloClient query
}
});
}
Here's the log on the server side I get if making a request via GraphiQL or Postman.
DEBUG 13749 --- [nio-8080-exec-8] o.s.w.f.CommonsRequestLoggingFilter : Before request [uri=/graphql]
Here's the log when the request comes from Apollo in the app.
DEBUG 13749 --- [io-8080-exec-10] o.s.w.f.CommonsRequestLoggingFilter : Before request [uri=/graphql]
DEBUG 13749 --- [io-8080-exec-10] o.s.w.f.CommonsRequestLoggingFilter : REQUEST DATA : uri=/graphql;payload={"operationName":"BookById","variables":{"id":"book-1"},"query":"query BookById($id: ID) { bookById(id: $id) { __typename name author { __typename firstName lastName } }}"}]
Could the issue be related to the __typename attribute that Apollo is adding? Or could it be due to "id" being defined as a simple parameter in the server side schema but it being a variable in the Android Studio definition of the query?
I just expected to receive the response back with no issues since it seems to work every other way. Even if I type in the query manually into my web browser I have no issues getting the right response, it's only when working with Apollo Client in G̶r̶a̶p̶h̶Q̶L̶ Android Studio that this issue pops up and I'm at a complete loss as to why. I appreciate any help people can offer. Thanks in advance.
Update: So looking around some more it looks like when sending a query via ApolloClient it sends the query as an object instead of as a JSON string. Now I'm thinking that's probably the cause of the 422 error. I've also read that allowing my GraphQL server to accept objects in addition to JSON strings is something I must enable. I'm not really sure how to go about that though, so does anyone with experience with Spring Boot have any advice on how I could go about doing that? Thanks.
I'm new to the Google App Engine, and I'm trying to make my first engine and connect it to my Android app. I have walked through this tutorial in order to learn about it:
https://cloud.google.com/endpoints/docs/frameworks/legacy/v1/java/helloendpoints-android-studio
I got it to work fine. I can access my app engine from my android app, and get the wanted response. The problem is, I want to restrict the endpoints of my API to my app's users only.
This is my API method (from the tutorial), and as for now, everyone can access my api's explorer and execute methods in it, as long as they are logged in to any Google account.
I want the users to be able to execute this method from my app only.
This is my app engine java file:
package com.example.Barda.myapplication.backend;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.UnauthorizedException;
import com.google.appengine.api.users.User;
import javax.inject.Named;
/**
* An endpoint class we are exposing
*/
#Api(
name = "myApi",
version = "v1",
clientIds = {Constants.ANDROID_CLIENT_ID},
audiences="firebase-wiki-race.appspot.com",
namespace = #ApiNamespace(
ownerDomain = "backend.myapplication.Barda.example.com",
ownerName = "backend.myapplication.Barda.example.com",
packagePath = ""
)
)
public class MyEndpoint {
/**
* A simple endpoint method that takes a name and says Hi back
*/
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String name) throws UnauthorizedException {
// if (user == null) throw new UnauthorizedException("User is Not Valid");
MyBean response = new MyBean();
response.setData("Hi, " + name);
return response;
}
}
This is constants class:
package com.example.Barda.myapplication.backend;
/**
* Contains the client IDs and scopes for allowed clients consuming your API.
*/
public class Constants {
public static final String ANDROID_CLIENT_ID = "*********************.apps.googleusercontent.com";
}
I have generated using my app's SH-1 and package name the ANDROID_CLIENT_ID.
I have searched online a lot, and read blogs and threads, but I couldn't make it work. Is this a possible thing to do? What am I doing wrong?
You'll want to follow the documentation's guide on adding authorization to the API backend. In this process you define a list of clients that are authorized to use your Endpoint.
Once that's done you can follow the guide on making authenticated calls from Android.
I am sagar, i am trying to implement the Parse Push-Notification in android using REST API (Service), and i am almost got success in implement the Push-Notification in Xamarin-Android using REST API. But i got stuck with one part in sending the Data into REST service. I trying to pass the ParseObject in service, but the in parse table there is a need of Object,(). I have tried to pass the ParseObject as below:
JsonConvert.SerializeObject(ParseUser.CurrentUser)
It convert ParseObject into array and array is not accepted in table and ,i got failed to save it in table. because there i a need of object.
I need solution or suggestion from developer guys. Yours help will be appreciated. I am trying the below code to achieve the result.
public static void RegisterPush(string regristrationId)
{
if (regristrationId != null) {
string appID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string restID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string masterID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
try {
var client = new RestClient ("https://api.parse.com");
var request = new RestRequest ("1/installations", RestSharp.Method.POST);
request.AddHeader ("Accept", "application/json");
request.AddHeader ("X-Parse-Application-Id", appID);
request.AddHeader ("X-Parse-REST-API-Key", restID);
request.Credentials = new NetworkCredential (appID, masterID);
request.Parameters.Clear ();
Console.Error.WriteLine ("ParseUser.CurrentUser-->"+ (ParseObject) ParseUser.CurrentUser);
//JsonConvert.SerializeObject(ParseUser.CurrentUser)
string strJSONContent = "{\"user\" :"+ JsonConvert.SerializeObject(ParseUser.CurrentUser)+",\"owner\":\"" + ParseUser.CurrentUser.ObjectId + "\",\"deviceType\":\"android\",\"GCMSenderId\":\"1234567890\",\"appName\":\"abcdefgh\",\"pushType\":\"gcm\",\"deviceToken\":\"" + regristrationId + "\"}";
Console.Error.WriteLine("json string-->"+ strJSONContent);
request.AddParameter ("application/json", strJSONContent, ParameterType.RequestBody);
client.ExecuteAsync (request, response => {
Console.Error.WriteLine ("response for android parse installation-->" + response.Content);
});
} catch (Exception ex) {
Console.WriteLine (ex.Message);
}
}
}`
Output:{"user" :[{"Key":"dealOffered","Value":4},{"Key":"dealRequested","Value":5},{"Key":"displayName","Value":"Cook"},{"Key":"email","Value":"lorenzo#gmail.com"},{"Key":"firstName","Value":"Lorenzo"},{"Key":"lastName","Value":"Cook"},{"Key":"mobileNumber","Value":9999999999.0},{"Key":"picture","Value":{"IsDirty":false,"Name":"tfss-afd25c29-6679-4843-842c-fe01f7fcf976-profile.jpg","MimeType":"image/jpeg","Url":"http://files.parsetfss.com/profile.jpg"}},{"Key":"provider","Value":"password"},{"Key":"userType","Value":"Merchant"},{"Key":"username","Value":"merchant#sailfish.com"},{"Key":"zipCode","Value":2342343}],"owner":"3cF1vHUXkW","deviceType":"android","GCMSenderId":"1234567890123","appName":"Sailfish","pushType":"gcm","deviceToken":"APA91bE3bsTIInQcoloOBE4kdLVVHVTRVtNyA1A788hYSC15wAVu8mUg-lwk7ZPk370rngrK7J6OoLmiM9HRr1CGPaBo6LCNrSUL7erBku4vepaFFkQzgqS6BcAemp"}
Error:{"code":111,"error":"invalid type for key user, expected *_User, but got array"}
maven
I found the solution in , parse xamarin docs, in one query , the way is simple, but i little bit hard to found out.
The issue is with the data passing in json format in REST, to pass any pointer using REST API, use as below.
The solution is as below:
`{
"user":{
"__type":"Pointer",
"className":"_User",
"objectId":"qYvzFzGAzc"
},
"owner":"qYvzFzGAzc",
"deviceType":"android",
"GCMSenderId":"123456789",
"appName":"NiceApp",
"pushType":"gcm",
"deviceToken":"APA91bFeM10jdrCS6fHqGGSkON17UjEJEfvJEmGpRM-d6hq3hQgDxKHbyrqAIxMnEGgbLEZf0E9AllHxiQQQCdEFiNMF1_A8q0n9tGpBE5NKhvS2ZGJ9PZ7585puWqz_1Z1EjSjOvgZ1LQo708DeL2KzA7EFJmdPAA"
}`
It looks like your column user is set up wrong. It should show as a Pointer<_User> not Pointer
If you load this class in your Data Browser, is the "user" key defined as a string, or a Pointer <_User>
This error seems to indicate that this is a string column, which is why the Parse.User object is not being accepted as a valid value. You might have tried setting a string on this key before, which in turn type-locked the "user" key as a string column.
Found it on the examples given on this page - https://www.parse.com/docs/rest
Have you check your REST API connection while passing ParseObject?
Because your error says:
Error:{"code":111,"error":"invalid type for key user, expected *_User, but got array"}
Here "code":111This error code comes when server refuse for connection
In my Android project I'm using Robospice with spring-android. Which works fine for all REST communication. But for the below request query parameter "=" is getting converted to "&". Because of this the request is getting failed.
Query String: tags=["keywords:default=hello"]
By checking the logs the request is converted as below for making call by the library.
http://XXX/rest/media/search?token=123&tags=%5B%22keywords:default&hello%22%5D
here "=" sign is converted to "&" in "keywords:default=hello"
Request Class
here tags = String.format("[\"keywords:default=%s\"]", mTag);
#Override
public MVMediaSearch loadDataFromNetwork() throws Exception
{
String search="";
if(!tags.equals(Constants.EMPTY_DATA))
search="&tags="+tags;
return getRestTemplate().getForObject( Constants.BASE_URL+"/media/search?token="+token+search, MVMediaSearch.class );
}
If I fire the URL in a browser, I'm getting error. And if I change the '&' sign to its corresponding url encoded value in browser, it works fine.
I also have the same issue.
For alternative, I use getForObject(java.net.URI, java.lang.Class).
URI uri = new URI(Constants.BASE_URL+"/media/search?token="+token+search);
getRestTemplate().getForObject(uri, MVMediaSearch.class );
http://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject(java.net.URI, java.lang.Class)
You can do something like this:
URI uri = new URI(
"http",
Constants.BASE_URL,
"/media/search?token=",
token,
search,
null);
String request = uri.toASCIIString();
take a look at THIS and see if you understand (you have to adapt to your code - this is not completely done for you)