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
Related
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.
Is there a way inside of Android Java to create an Entity Key?
For example, inside the Cloud Endpoints Java module code you can do this:
Key<User> userKey= Key.create(User.class, userId);
or with an Ancestor:
Key<Post> postKey= Key.create(userKey, Post.class, postId);
How can you do the above in the Android generated client library? I want to see if I can create a key in Android and pass it to an API method (probably as a websafeKey userKey.getString()).
BONUS: How can you do this with the objective-C Cloud Endpoints client library?
I doubt you want either the datastore nor objectify code in your Android App. That simply not where that belongs. So the way to go is to look at the source of the KeyFactory. In the method keyToString() we can see that most of the magic happens in the class KeyTranslator in method convertToPb().
Here's the code of convertToPb:
public static Reference convertToPb(Key key) {
Reference reference = new Reference();
reference.setApp(key.getAppId());
String nameSpace = key.getNamespace();
if (!nameSpace.isEmpty()) {
reference.setNameSpace(nameSpace);
}
Path path = reference.getMutablePath();
while (key != null) {
Element pathElement = new Element();
pathElement.setType(key.getKind());
if (key.getName() != null) {
pathElement.setName(key.getName());
} else if (key.getId() != Key.NOT_ASSIGNED) {
pathElement.setId(key.getId());
}
path.addElement(pathElement);
key = key.getParent();
}
Collections.reverse(path.mutableElements());
return reference;
}
And here's the code of keyToString()
public static String keyToString(Key key) {
if (!key.isComplete()) {
throw new IllegalArgumentException("Key is incomplete.");
} else {
Reference reference = KeyTranslator.convertToPb(key);
return base64Url().omitPadding().encode(reference.toByteArray());
}
}
Now what you want to do, is to replace the Key stuff in convertToPb with "normal" parameters (type, name/key, parent type, parent name/key) and thus rewrite the method to create a websafeKey without an actual Key object.
It would be much easier though if your app engine API simply accepted the ids and you'd recreate the key on the appengine side of things. My APIs are usually structured like
/user/<userId>/post/<postId>
if i assume an Entity that looks like this
#Entity public class Post {
#Parent Ref<User> user
#Id id; }
Regarding the bonus: What (the heck) is an Objectify Cloud Endpoint? I know Cloud Endpoints and Objectify, but i have not heard of a product that combines the two.
I am newbie in sparql queries. I try to send a sparql query from my android device to an EndPointURI remote server so i can get the results. I want to select all the results that match with "salmon", as it seems in my code below.
My issue is in this line: "ResultSet resultSet = qe.execSelect();".
When i try to take the results i get
no authentication challenges found at libcore.net.http.httpURLConnectionImpl.get Authorization Credentials
and this because myURL wants authentication credentials and i dont know how to send them.
Any ideas of how can i send username and password succesfully?
My imports are :
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.Syntax;
the .jars in my libs file are:
androjena_0.5,
arqoid_0.5,
icu4j_3_4,
iri-0.8,
lucenoid_3.0.2,
slf4j-android-1.6.1-RC1
and finally my function
public String queryRemoteSparqlEndpoint()
{
String username="lala";
String password="lala";
String queryString = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> select ?sp"
+where {"
+"<URL>"
+"?sp \"salmon\"."
+"}";
String sparqlEndpointUri = "myURL/sparql";
Query query = QueryFactory.create(queryString, Syntax.syntaxARQ);
query.setLimit(10);
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});
QueryExecution qe = QueryExecutionFactory.sparqlService(sparqlEndpointUri, query);
ResultSet resultSet = qe.execSelect();
while (resultSet.hasNext())
{
//.....
}
return results.toString();
}
Thank you in advance.
I don't know which version of Jena is being run in androjena 0.5 but the current version of Jena has support for
sparqlService(String service, Query query, HttpAuthenticator authenticator)
where HttpAuthenticator is from Apache HTTP Client. I don't know if this works on androjena.
If the code does not support it, you can make the call directly with native HTTP operations and pass the resulting input stream to a result set parser (see ResultSetFactory).
UPDATE 27th January 2013
I have now resolved this, Please check the accepted answer.
I am having trouble to get my refresh token and my access token when using the server side flow between my Android Application and my PHP server.
So I have managed to get my One Time Code by using the below:
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
Bundle appActivities = new Bundle();
appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
"http://schemas.google.com/AddActivity");
String scopes = "oauth2:server:client_id:" + SERVER_CLIENT_ID +
":api_scope:" + SCOPE_STRING;
try {
code = GoogleAuthUtil.getToken(
OneTimeCodeActivity.this, // Context context
mPlusClient.getAccountName(), // String accountName
scopes, // String scope
appActivities // Bundle bundle
);
} catch (IOException transientEx) {
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
System.out.println(transientEx.printStactTrace());
return "Error";
} catch (UserRecoverableAuthException e) {
// Recover
code = null;
System.out.println(e.printStackTrace());
OneTimeCodeActivity.this.startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
System.out.println(authEx.printStackTrace());
return "Error";
} catch (Exception e) {
System.out.println(authEx.printStackTrace());
}
}
Which will then store the token in the variable "code" and I call up the async task as
task.execute();
The code above will always bring up a popup message and throw UserRecoverableAuthException Need Permission that requires the user to grant offline access, which means the above will need to be called twice to retrieve the code and store it in "code"
I am now trying to send this across to my server which is implemented in PHP.
I have used the quick start https://developers.google.com/+/quickstart/php and managed to get that working.
In here, there is a sample signin.php
In here and according to the documentation this already implements a One Time Authorisation Server Side Flow.
So now my problem is sending this One Time Code to the server.
I used the photohunt Android Auth example for this located here.
https://github.com/googleplus/gplus-photohunt-client-android/blob/master/src/com/google/plus/samples/photohunt/auth/AuthUtil.java
I used the "authorization" method of the code and called up signin.php/connect through a post method shown below
$app->post('/connect', function (Request $request) use ($app, $client) {
$token = $app['session']->get('token');
if (empty($token)) {
// Ensure that this is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
return new Response('Invalid state parameter', 401);
}
// Normally the state would be a one-time use token, however in our
// simple case, we want a user to be able to connect and disconnect
// without reloading the page. Thus, for demonstration, we don't
// implement this best practice.
//$app['session']->set('state', '');
$code = $request->getContent();
// Exchange the OAuth 2.0 authorization code for user credentials.
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
// You can read the Google user ID in the ID token.
// "sub" represents the ID token subscriber which in our case
// is the user ID. This sample does not use the user ID.
$attributes = $client->verifyIdToken($token->id_token, CLIENT_ID)
->getAttributes();
$gplus_id = $attributes["payload"]["sub"];
// Store the token in the session for later use.
$app['session']->set('token', json_encode($token));
$response = 'Successfully connected with token: ' . print_r($token, true);
}
return new Response($response, 200);
});
Now when I send the code using the above implementation, I get an 500 messages that says the below
Google_AuthException Error fetching OAuth2 access token, message: 'invalid_grant'
in ../vendor/google/google-api-php-client/src/auth/Google_OAuth2.php line 115
at Google_OAuth2->authenticate(array('scope' => 'https://www.googleapis.com/auth/plus.login'), '{ "token":"xxxxxxxx"}') in ../vendor/google/google-api-php-client/src/Google_Client.php line 131
at Google_Client->authenticate('{ "token":"xxxxxxx"}') in ../signin.php line 99
at {closure}(object(Request))
at call_user_func_array(object(Closure), array(object(Request))) in ../vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php line 117
at HttpKernel->handleRaw(object(Request), '1') in ../vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php line 61
at HttpKernel->handle(object(Request), '1', true) in ../vendor/silex/silex/src/Silex/Application.php line 504
at Application->handle(object(Request)) in ../vendor/silex/silex/src/Silex/Application.php line 481
at Application->run() in ../signin.php line 139
Funny enough I have had to worked once where I did receive a 200, but I cannot recreate it.
So I know I have definitely got the implementation wrong, but I have no clue on how to send it and get my refresh token. I can't find anywhere on the web that explains this. Is someone able to help me please.
UPDATE 16 Jan 2014
Using https://www.googleapis.com/oauth2/v1/tokeninfo?access_token= I can see that the token being produced from getToken is valid and is indeed valid for 1 hour.
I can confirm the json formation is correct by changing the way I am inputting into the Post request and if I don't do it properly I get a total failure.
Now I am going deeper into the php and look at this section Google_OAuth2.php line 115 where it is breaking it is throwing a Google_AuthException. The code is below and this is provided in the quick starter pack
/**
* #param $service
* #param string|null $code
* #throws Google_AuthException
* #return string
*/
public function authenticate($service, $code = null) {
if (!$code && isset($_GET['code'])) {
$code = $_GET['code'];
}
if ($code) {
// We got here from the redirect from a successful authorization grant, fetch the access token
$request = Google_Client::$io->makeRequest(new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), array(
'code' => $code,
'grant_type' => 'authorization_code',
'redirect_uri' => $this->redirectUri,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
)));
if ($request->getResponseHttpCode() == 200) {
$this->setAccessToken($request->getResponseBody());
$this->token['created'] = time();
return $this->getAccessToken();
} else {
$response = $request->getResponseBody();
$decodedResponse = json_decode($response, true);
if ($decodedResponse != null && $decodedResponse['error']) {
$response = $decodedResponse['error'];
}
throw new Google_AuthException("Error fetching OAuth2 access token, message: '$response'", $request->getResponseHttpCode());
}
}
$authUrl = $this->createAuthUrl($service['scope']);
header('Location: ' . $authUrl);
return true;
}
I edit the code above to make sure the code, the client id and secret were correct and they were. So that is where I am now, I don't think it is scope issues as well as I hard coded it in the client setup and still does not work. Not too sure.
UPDATE 23rd January
OK, I think it is a time issue. I used https://developers.google.com/+/photohunt/android and base my design on the BaseActivity in the Photohunt using the AuthUtil, and I get invalid grant on my server. How do I move the time back on my server in code. I read somewhere I can do time() - 10 somewhere but not sure where...
It sounds like you may be sending the same authorization code multiple times. On Android GoogleAuthUtil.getToken() caches any tokens that it retrieves including authorization codes.
If you ask for a second code without invalidating the previous code, GoogleAuthUtil will return the same code. When you try to exchange a code on your server which has already been exchanged you get the invalid_grant error. My advice would be to invalidate the token immediately after you retrieve it (even if you fail to exchange the code, you are better off getting a new one than retrying with the old one).
code = GoogleAuthUtil.getToken(
OneTimeCodeActivity.this, // Context context
mPlusClient.getAccountName(), // String accountName
scopes, // String scope
appActivities // Bundle bundle
);
GoogleAuthUtil.invalidateToken(
OneTimeCodeActivity.this,
code
);
invalid_grant can be returned for other reasons, but my guess is that caching is causing your problem since you said it worked the first time.
This issue is now resolved. This was due to the implementation on the One Time Code exchange with the server
As specified in the my issue above, I used the photohunt example to do the exchange with my server. The Android code can be found on the below link
https://github.com/googleplus/gplus-photohunt-client-android/blob/master/src/com/google/plus/samples/photohunt/auth/AuthUtil.java
One line 44 it reads this
byte[] postBody = String.format(ACCESS_TOKEN_JSON, sAccessToken).getBytes();
This will only work if on the server side you handle the JSON. I did not.
When calling up $client->authenticate($code); in php, $code had a JSON string and therefore when calling https://accounts.google.com/o/oauth2/token the authorization code was wrong.
So it was easy as I was not sending the code in the right format.
I found this out when digging and testing https://accounts.google.com/o/oauth2/token and created a manual cURL to test the token.
As provided in the Google+ API it was stated that all examples included a One Time Code exchange, but I think the code across all platform are not consistent and one has to double check themselve to make sure everything flows correctly, which was my mistake.
I am creating an (iphone/android) mobile app using appcelerator titanium. I have a problem using Ti.App.Properties,
I want to save the user's login data (username and password), I used Ti.App.Properties's getList and setList methods to get and set username and password at app startup. It is working fine on iPhone, but on android the data (username and password) are not retrieved at app startup.
here is the code that is executed at app startup :
var userDataArray=[{title:'name',value:''},
{title:'password',value:''}];
if(Ti.App.Properties.hasProperty("userDataArray"))
{
userDataArray = Ti.App.Properties.getList("userDataArray");
}
else
{
Ti.App.Properties.setList("userDataArray",userDataArray);
}
if((Ti.App.Properties.getList("userDataArray")[0].value.length==0)||(Ti.App.Properties.getList("userDataArray")[1].value.length==0))//check if name, password have no values.. on android, this is always the case, which is not correct
{
//go to login page
}
else if((Ti.App.Properties.getList("userDataArray")[0].value.length>0)&&(Ti.App.Properties.getList("userDataArray")[1].value.length>0))//if both username and password exist
{
//start
}
Thank you
i think your overall approach is flawed, you dont need an array just an map
// save the values as a string..
Ti.App.Properties.setString({"username":"myname", "password":"mypassword"}, "CREDENTIALS");
// retrieve the values as a string, but parse it back into an object
var credObject = JSON.parse(Ti.App.Properties.getString("CREDENTIALS"));
// dump the output
Ti.API.debug("Username "+ credObject.username);
Ti.API.debug("Password "+ credObject.password);
two remarks :
arguments for .setString() is opposite, ie Name then Value
Value must be a string, so you have to stringify() it or enter it as a string
I know this is old, but it's still relevant today as there's not a huge amount of help with Titanium. I handle this in two parts.
Part 1) After the user's credentials have been authenticated...
var username = "some username";
var password = "some password";
// Build the object and then convert it to a json string.
oCredentials = new Object();
oCredentials.username = username;
oCredentials.password = password;
var stringCredentials = JSON.stringify(oCredentials);
// Save the credentials
Ti.App.Properties.setString("Credentials", stringCredentials);
Part 2) Before you prompt the user with the login window/popup/whatever...
// Look for credentials
(function() {
var storedCredentials = Ti.App.Properties.getString("Credentials");
if (storedCredentials){
var oJson = JSON.parse(storedCredentials);
// Call your authentication function
// For example, autoAuthenticate(oJson.username, oJson.password);
} else {
// kick the user out to your login window
// For example, $.loginWindow.open();
}
})();