Use Gmail account to log into my App? - javascript

For the android app I'm working on, it requires the creation of a profile to send and recieve content to other users. For the login process, is it possible for the user to login with the Gmail account associated on the phone? Which would be the same account that is active to use google play.
This would make the whole login process very smooth, and I think it would be the best possible scenario.
Many thanks!

Yes it is possible, and it is quiet simple. Before you start you need to add, one permission to you AndroidManifest.xml
<uses-permission android:name="android.permission.GET_ACCOUNTS"></uses-permission>
It allows you to read the accounts associated with the device. Then you do the following inside the app:
Account[] accounts = AccountManager.get(context).getAccountsByType("com.google");
This will return all google accounts of the user. In your case maybe you need only the emails, so here is a quick static function that will give them to you:
public static String[] getAccounts(Context context) {
Account[] accounts = AccountManager.get(context).getAccountsByType("com.google");
String[] names = new String[accounts.length];
for (int i = 0; i < accounts.length; ++i) names[i] = accounts[i].name;
return names;
}
This function will return a string array of all gmail emails (Google accounts) on the device.
However, if you need to "talk" with some Google services for some more information, you will have to do the following. First add one more permission to the manifest:
<uses-permission android:name="android.permission.USE_CREDENTIALS"></uses-permission>
This permission will allow your app to use the use credentials to identify the user in front of some Google service. It will NOT give you the credentials(passwords).
To use some Google service you will need a token. Here it is a quick function for that:
public static String getToken(Activity activity, String serviceName) {
try {
Bundle result = AccountManager.get(activity).getAuthToken(account, serviceName, null, activity, null, null).getResult();
return result.getString(AccountManager.KEY_AUTHTOKEN);
} catch (OperationCanceledException e) {
Log.d("Test", "Operation Canceled");
} catch (AuthenticatorException e) {
Log.d("Test", "Authenticator Exception");
} catch (IOException e) {
Log.d("Test", "Auth IOException");
}
return null;
}
Once you have the token you just the HTTP API they have and you have fun :-)

Related

I need to get the email used for signing in to the MS sign in to my application code. How do I get it?

I have an application that uses Azure AD sign in through MS sign-in page. However, once authenticated I want to get the email ID used for authentication to my application code so I can verify it against the application registered users.
Is there any way to get it?
Code:
Controller
public IActionResult SignIn([FromRoute] string scheme)
{
scheme = scheme ?? AzureADDefaults.AuthenticationScheme;
var redirectUrl = Url.Content("~/");
return Challenge(
new AuthenticationProperties { RedirectUri = redirectUrl },
scheme);
}
Startup.cs
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
});
Login.cshtml
<li><a asp-controller="Accountslogin" asp-action="SignIn" >Sign in</a></li>
Please make sure you are collecting and sending the email Address attribute to the application.
User attributes are values collected on sign up. Claims are values about the user returned to the application in the token. You can create custom attributes for use in your directory.
For more detail information please refer similar question

Cordova fingerprint authentication on server

I am trying to create a authentication mechanism in my (cordova) app for android that will allow my users to sign in using a password and username, or allow them to scan their finger in order to sign in.
How can one verify a fingerprint registered on a client, server side? is this even possible at all using Cordova ? I tried transmitting the result of a finger scan to my server: this looked like:
FingerprintAuth.isAvailable(function(result) {
if (result.isAvailable) {
if(result.hasEnrolledFingerprints){
FingerprintAuth.show({
clientId: client_id,
clientSecret: client_secret
}, function (result) {
alert(JSON.stringify(result));
$http.post('http://192.168.149.33:3000/authorize', result).then(
function(response) {}
);
if (result.withFingerprint) {
$scope.$parent.loggedIn = true;
alert("Successfully authenticated using a fingerprint");
$location.path( "/home" );
} else if (result.withPassword) {
alert("Authenticated with backup password");
}
}, function(error) {
console.log(error); // "Fingerprint authentication not available"
});
} else {
alert("Fingerprint auth available, but no fingerprint registered on the device");
}
}
}, function(message) {
alert("Cannot detect fingerprint device : "+ message);
});
Server side i am receiving the following data (3 seperate scans):
{ withFingerprint: 't8haYq36fmBPUEPbVjiWOaBLjMPBeUNP/BTOkoVtZ2ZiX20eBVzZAs3dn6PW/R4E\n' }
{ withFingerprint: 'rA9H+MIoQR3au9pqgLAi/EOCRA9b0Wx1AvzC/taGIUc8cCeDfzfiDZkxNy5U4joB\n' }
{ withFingerprint: 'MMyJm46O8MTxsa9aofKUS9fZW3OZVG7ojD+XspO71LWVy4TZh2FtvPtfjJFnj7Sy\n' }
The patterns seems to vary every time, is there a way one can link the finger print to for example a pattern saved under a user on a database ?
Short answer
The strings returned by this API are not "fingerprint patterns". So you won't be able to authenticate the way you're thinking...
Long answer
Let's start by looking at the source code of the API it looks like you're using.
Looking at this file we see these methods:
public static void onAuthenticated(boolean withFingerprint) {
JSONObject resultJson = new JSONObject();
String errorMessage = "";
boolean createdResultJson = false;
try {
if (withFingerprint) {
// If the user has authenticated with fingerprint, verify that using cryptography and
// then return the encrypted token
byte[] encrypted = tryEncrypt();
resultJson.put("withFingerprint", Base64.encodeToString(encrypted, 0 /* flags */));
} else {
// Authentication happened with backup password.
resultJson.put("withPassword", true);
// if failed to init cipher because of InvalidKeyException, create new key
if (!initCipher()) {
createKey();
}
}
createdResultJson = true;
// ...
/**
* Tries to encrypt some data with the generated key in {#link #createKey} which is
* only works if the user has just authenticated via fingerprint.
*/
private static byte[] tryEncrypt() throws BadPaddingException, IllegalBlockSizeException {
return mCipher.doFinal(mClientSecret.getBytes());
}
Look at what's being put to "withFingerprint". It's a Base64 encoding of the encrypted client secret. Technically, this is your authentication. You would use this token to authenticate requests and your server would decrypt and validate the client secret.
Summary
Fingerprinting adds a level of security, but it is not the only means of security. A relationship needs to be established with the device and server beforehand.
I found this diagram to be helpful in understanding the intent of android's fingerprint authentication (ref: http://android-developers.blogspot.com/2015/10/new-in-android-samples-authenticating.html)
You can't authenticate fingerprint on the server, fingerprints are stored or authenticated using Live Scan/Biometric template. Authentication is done by comparing the current scan template with previously stored templates
First of all you don't have access to these stored templates(Not provided by the OS providers/Phone Manufacturers) and If we assume that you have access to those templates, then an efficient algorithm (Image based /Pattern based ) is required to compare the current template with previously stored templates. You can't simply authenticate it by string comparison.
Use cordova-plugin-fingerprint-aio for fingerprint authentication .
For further info you can consult https://www.npmjs.com/package/cordova-plugin-fingerprint-aio .

Looking for a Cloud Code ( javascript ) expert, dealing with Installations and channels

So my biggest problem is that I never wrote a single line of javascript before but as I developing my application it has become more and more clear I have to use it in Cloud Code.
I have a parse class named Groups, in this I store groups with the following data:
Name, Description, Users, Requests.
If a user creates a group from their device it will be here with the given name, description and the user pointer in it, and I'm using the new objectId with a + "C" char (sometimes objectId starts with a number but its not valid for a channal) to subscripte that user ( installation ) to a channel, so if I query the groups, I get the objectId and I can send every member of the group a push notification.
My first problem is here, that if i store the channel to a installation object in parse with the following code:
groups = new Groups();
groups.setName(groupName.getText().toString());
groups.put("members", ParseUser.getCurrentUser());
groups.setDesc(description.getText().toString());
groups.saveEventually(new SaveCallback() {
#Override
public void done(ParseException e) {
//Subscribe to push
ParsePush.subscribeInBackground("C" + groups.getObjectId(), new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.d("com.parse.push",
"successfully subscribed to the broadcast channel.");
} else {
Log.e("com.parse.push", "failed to subscribe for push", e);
}
}
});
If the user has multiple devices then he wont get the push notifications on every device just on that where he created the group. I searched for it and I am sure I have to use a Parse Cloud function for the subscribing process and with it all the Installations of a specific user will subscribe to the same channels.
Here is my first problem. Can anyone help with it or just give me some reference to solve this (I read all the Cloud Documentation)
Notice:
After the registration I add the user pointer to the Installation like this:
ParseInstallation.getCurrentInstallation().put("user", ParseUser.getCurrentUser());
My second problem:
As I find others have problem with it too and there was some solutions but my problem is a bit more complex. So as I noticed, if I send a client side notification from a device, it will be delivered to the selected channels, it working fine, but if I delete the application then reinstall it, and I'm sending client side notification, it wont delete the multiple installation objects for the device and I will get the notification twice
(I know that if I send notification from parse dashboard it is doing the delete job).
So I need a cloud function that is checking that if there is an other installation with the same user and androidId ( added at install, get it from Android Security ) , if there, then delete it, check if there is an other installation with the same user but not with the same andoidId, copy that installation's channels to my new one and then save the new installation.
Same as above, reference, example code, anything.
I think it will be usefull for others too and hope that someone can help me.
(P.S.: If you need more information please comment, I will always answer in 24 hours)
Whenever the app opens, make sure that the device subscribes to the channel:
"user_" + ParseUser.getCurrentUser().getObjectId()
Then you will send the push notifications to all the devices that the user is signed into.
First problem solution:
I am showing the Groups in a listView, and when a new group is added, the list have to refresh itself, it do it with this method:
public static void updateData() {
ParseQuery<Groups> query = ParseQuery.getQuery("Groups");
query.whereEqualTo("members", ParseUser.getCurrentUser());
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_THEN_NETWORK);
query.findInBackground(new FindCallback<Groups>() {
#Override
public void done(List<Groups> parseObjects, ParseException e) {
if(e != null) {
return;
}
for( int i = 0; i < parseObjects.size(); i++){
Groups iter = parseObjects.get(i);
ParsePush.subscribeInBackground("C" + iter.getObjectId());
}
groupsAdapter.clear();
groupsAdapter.addAll(parseObjects);
}
});
}
With this method (added to onResume) every time I resume to the application it refreshes the list and the device subscribing to all the channels created from the objectId's of the groups where he is a member.
I know it is not a well solution but for now it is fine for me.
And still looking for a better one and for my second question.

Having trouble grasping how to securely sign JWT with Private Key

I'm looking at this example here which refers to the javascript functionality of JWT
I am trying to use javasrcipt to sign a piece of data. However, it says I have to use a Private RSA Key and it doesn't allow you to use a public key.
My goal was once a form is submitted via PHP, call this javascript function and encrypt the data.
Pardon my ignorance, but how can you use a private RSA key in javascript and keep it private at the same time?
It appears that you have to give it a private key somehow and wouldn't that private key be visible to a user using simple developer tools in the web browser?
function _genJWS() {
var sHead = '{"alg":"RS256"}';
var sPayload = '{"data":"HI","exp":1300819380}';
var sPemPrvKey = document.form1.pemprvkey1.value;
var jws = new KJUR.jws.JWS();
var sResult = null;
try {
sResult = jws.generateJWSByP1PrvKey(sHead, sPayload, sPemPrvKey);
document.form1.jwsgenerated1.value = sResult;
} catch (ex) {
alert("Error: " + ex);
}
}
What your are looking for is not JWS (signed), but JWE (encrypted).
If you want to send secured data to a server using JWE, you must :
get the public key of the server
encrypt your data using this public key and produce a JWE
send your JWE to the server.
As far as I know, there is no javascript library able to produce JWE (I may be wrong, but I found nothing).

I want to use Javascript to call .NET WebService, How to limit the access?

I have a .net webservice like http://tempurl.org/webservice.asmx
I want to call it using Javascript, maybe some jquery lib.
Q1: How to limit the access only to myself?
Q2: or How to implement a role based authentication.
Edit:
I want to deploy the webservice independently like:
ProjectA
ProjectB
ProjectWebService
I need People login in ProjectA and ProjectB and can use ProjectWebService.
just a suggestion, as you know theres many ways to skin a cat so heres one.
Firstly enable session state across calls to the service using
[WebMethod(EnableSession = true)]
Then have a web service method for login that saves the user details to the session, this supports the standard Membership provider for asp.net, warning sample code
public bool Login(string userName, string password)
{
//validate login
var user = Membership.GetUser(userName);
var valid = Membership.ValidateUser(user.UserName, password));
if (valid)
HttpContext.Current.Session["user"] = user;
return valid;
}
Then you can in a web service method validate against the user.
public void SomeServerMethod()
{
var user = HttpContext.Current.Session["user"];
if (user == null)
throw new Exception("Please login first");
if (user.IsInRole("FooRole")
DoStuff();
else
throw new Exception("Seriously? dude you dont have those rights");
}
To counter network easedropping best go to Https, good luck :)

Categories