Log in to my web from a chrome extension - authentication

I've got a web where logged in users can fill out a form to send information. I wanted my users to do this from a chrome extension too. I managed to get the form to sen information working but I only want to be logged in users to be able to do that. It's like a twitter or Springpad extension when the user first opens up the extension, it would have to log in or register. I saw the following answer at stack overflow: Login to website with chrome extension and get data from it
I gave it a try and put this code in background.html:
function login() {
$.ajax({
url: "http://localhost/login", type: "GET", dataType: "html", success: function() {
$.ajax({
url: "http://localhost/login", type: "POST", data: {
"email": "me#alberto-elias.com",
"password": "mypassword",
},
dataType: "html",
success: function(data) {
//now you can parse your report screen
}
});
}
});
}
In my popup.html I put the following code:
var bkg = chrome.extension.getBackgroundPage()
$(document).ready(function() {
$('#pageGaffe').val(bkg.getBgText());
bkg.login();
});
And on my server, which is in node.js, I've got a console.log that shows user information when he logs in, so I saw that when I load my extension, it does log in. The problem is how can I get the user to log in by itself, instead of manually putting my details in the code, how to stay logged in in the extension and when submitting the form, sending the user's details to the web.
I hope I've managed to explain myself correctly.
Thanks.

Before answering this question I would like to bring to your notice that you can make cross origin xhr from your content scripts as of Chrome 13 if you have declared proper permissions. Here is the extract from the page
Version note: As of Chrome 13, content scripts can make cross-origin requests to the same servers as the rest of the extension. Before Chrome 13, a content script couldn't directly make requests; instead, it had to send a message to its parent extension asking the extension to make a cross-origin request.
Coming to the point. You simply have to make an XmlHttpRequest to your domain from your extension (content script or background page) and wait for the response.
At Server
Read the request and session cookie. If session is valid send proper response, else send an error code. 401 or anything else.
At client
If response is proper display it, else display a login link directing to login page of your website.
How it works:
It will work if cookies in user's browser is enabled. Whenever user logs in to your website your server sets a session cookie which resides in user's browser. Now with every request that the browser sends to your domain, this cookie is transmitted. This cookie will be transmitted even if the request is from a Google Chrome Extension.
Caveat
Make sure you display proper cues to user indicating that they are logged in to your application. Since your UI will be mostly inside the extension, it is possible that user might not be aware of their valid session with your website and they might leave an active session unattended which might be abused if user is accessing it from a public internet kiosk.
Reference
You can take a look at a similar implementation that I have done with my extension here.

So the user logs into your server and you know that. I am a bit confused if you then want the user to be able to browse your website with those credentials or a third party website with those credentials.
If it is your website then you should be able to set a cookie that indicates whether they are logged in. Then detect this server side when they navigate your site.
If it is a third party site then the best you can do is create a content script that either fills out the login form and autosubmits for them or analyze the login post data and send it along yourself, then force a refresh.

Related

The Cypress test does not open the Powerapps page

I'm trying to run simple cypress test and get error like this:
but if i change visit url to another - it opens normally:
I cant understand why this does this error come with this url:
"baseUrl":"https://apps.powerapps.com/play/f1t75er8-03c9-4cc7-996d-6743cd7eac4a"
another visible error:
code:
describe("Create request", () => {
it("Should have a link that navigates to office365 login", () => {
cy.visit("/");
cy.get('div[class="loginNeededText_uf5ohz"]').contains('Sign in to start using Power Apps');
});
});
P.S. Also can't load https://apps.powerapps.com/ page. Error:
In general
With Cypress, you should not try to visit or interact with sites or servers you do not control. The main purpose of Cypress is testing, so when you try to do anything else with it, the task will become significantly more complicated (you can read more about it in the Cypress documentation).
If you really need information from a 3rd party site, it is recommended you do it through an API — mainly with the cy.request() method (e.g., Microsoft has quite an extensive documentation on how to work with the Office 365 Management API).
Your case
When you visit the apps.powerapps.com, you are being redirected to the Microsoft login page — it has a different domain name, which breaks a same-origin policy causing the cross-origin error in the Cypress console.
Seems that the page you specified in the baseUrl returns a 404 status code, along with some ugly CORS errors in the console, which suggest an issue with the app itself. After you solved those, you would most probably face the need of authentication anyway, and it is better to do it through an API.
When I use your base URL https://apps.powerapps.com/play/f1t75er8-03c9-4cc7-996d-6743cd7eac4a I see only blank screen and 404 error in the console, I am not redirected to login.
Maybe your URL should be https://apps.powerapps.com and after you login you can navigate to "/play/f1t75er8-03c9-4cc7-996d-6743cd7eac4a".

need to mock POST request in cypress

UPDATED 9/16:
I've reworded my question. I'm trying to use cypress to test a work application that has an Angular frontend(http://localhost:4200) and a .NET Core backend (http://localhost:5000).
When the app starts, a login page loads with username and password fields. The cypress code test fills in the username and password and clicks the submit button, as show in my code below.
When the login (submit) button is clicked, it triggers a POST request to the .NET Core backend. The request submits the username and password and if the user is verified, a token comes back in response. The token is added to session storage and the user is logged in. It is this token value in the session storage that signifies the user is logged in. With the token added, the user gets redirected to the homepage.
Now the backend is NOT running. I need to simulate this POST request so the cypress test can get to the actual homepage.
I think I need to stub this POST request but I can't get this code to work. The request just aborts and looking at the console it says the request was not stubbed.
Here's my updated cypress code:
const username = 'johndoe';
const password = 'pass1234';
cy.server();
cy.get('h1').should('contain', 'Login');
cy.get('input[placeholder=Username]').type(username);
cy.get('input[placeholder=Password]').type(password);
cy.get('button[type=submit]').click();
cy.route({
method: 'POST',
url: 'http://localhost:5000/Authentication/Login',
response: {
access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' // some random characters
}
});
You might have more success if you set up the route before invoking the POST (clicking submit),
cy.server();
cy.route({
method: 'POST',
url: 'http://localhost:5000/Authentication/Login',
response: {
access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' // some random characters
}
});
...
cy.get('button[type=submit]').click();
However, if your app uses native fetch as opposed to XHR, core Cypress does not catch this type of request. You have to add a polyfill which essentially modifies the window.fetch method to allow cy.route() to succeed.
cypress.json
{
"experimentalFetchPolyfill": true
}
Please note the limitations section,
Limitations
The experimental polyfill is not foolproof. It does not work with fetch calls made from WebWorkers or ServiceWorker for example. It might not work for streaming responses and canceled XHRs. That's why we felt the opt-in experimental flag is the best path forward to avoid breaking already application under tests.

How to get daemon access token for self account

I am trying to create a web app whose main task is fixing appointment.
I do not want to access any mail data of the logged in user.
I only want to implicitly login using an outlook account (my account) to which I have admin access. I want to connect with this account, fetch its calendar events and display the events to the logged in user so that the user can select any available spots.
I have registered my app in the azure portal and provided all the application permissions (earlier I tried with Delegated permissions as well; but I guess delegated permissions are not for my use case).
Thereafter, I tried to fetch the token for my profile using:
this.http.post(`https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/oauth2/v2.0/token`,
{
client_id: 'my-client-uuid',
scope: 'https://graph.microsoft.com/.default',
grant_type: 'client_credentials',
client_secret: '****myclientsecret****'
},
{
headers: {
Host: 'login.microsoftonline.com',
'Content-type': 'application/x-www-form-urlencoded'
}
}
).subscribe(resp => {
console.log(resp);
});
as suggested in this article.
However, my request fails while doing this and states that the request body must contain 'grant_type' when I am clearly sending that.
Can someone please suggest me how I can implicitly get data from my own outlook account in a web app.
Update: I used the suggestion from this, appears that the request is going through now. However, the browser throws CORS error saying that the server didn't have appropriate headers.
Update 2: Found this link, which seems to address the exact issue I am facing. I however already have the redirect URI for SPA. The issue still persists.

How do I get react-native-inappbrowser-reborn to trigger success upon successful Facebook login

I'm trying to setup a manual flow for Facebook login, as per the docs at: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/
I've got my test Facebook app working as expected, i.e., I can login using a private web browser window fine. The URL I'm using is:
https://facebook.com/v3.3/dialog/oauth?client_id=<app_id>&display=popup&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html
Now within my React-Native app, I'm using react-native-inappbrowser-reborn to present a SFAuthenticationSession on iOS. As per their docs (at https://www.npmjs.com/package/react-native-inappbrowser-reborn), I'm doing the following:
const redirectUri = "https://www.facebook.com/connect/login_success.html"
const url = "https://facebook.com/v3.3/dialog/oauth?client_id="+appId+"&display=popup&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html"
InAppBrowser.isAvailable()
.then(() => {
InAppBrowser.openAuth(url, redirectUri, {
// iOS Properties
dismissButtonStyle: 'cancel',
// Android Properties
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: true,
})
.then((response) => {
// Only gets to this point if user explicitly cancels.
// So this does not trigger upon successful login.
})
// catch handlers follow
Using the above, my app correctly open up an in-app browser and I can login fine using a test user for my test app. Upon successful login though, I don't get redirected back to the .then completion handler. It just stays in the in-app browser view and I see the same message from Facebook that I see when logging in using a web browser. It says something like "Success. Please treat the url the same as you would a password", or something like that.
I may be missing something here, but I thought the purpose of passing redirectUri as an argument to openAuth was so that upon redirection to that URI, the completion handler would be triggered.
Question: How do I redirect back to the completion handler upon login success?
I think that you already have a solution but thought it might be useful for someone else facing this issue. If you don't have a solution so far follow my instructions:
You can't directly redirect back to your application using deep link, since Facebook will not call a link `like myapplicationname://mycustompath´. It's only possible to call links using the https-protocol (https://...).
The solution I'd suggest you to use is to redirect using your own API (Facebook -> Your API -> Deep Link Redirection). You will understand why this is required in the most of the real world applications at the end of the instructions.
Starting from your react-native app call the authorize endpoint of Facebook with a redirection to your application and set the global deeplink of your app as redirect uri.
InAppBrowser.close();
InAppBrowser.openAuth("https://graph.facebook.com/oauth/authorize?client_id=YOURCLIENTID&redirect_uri=https://YOURDOMAIN:PORT/auth/facebook", "{YOURAPPSDEEPLINKNAME}://{SOMEPATHYOUWANTTOEND}")
.then((response) => {
handleAuthorized(response, LOGINTYPE.FACEBOOK);
});
Now after login you'll be redirected to your API with the authorization code token as query parameter (e.g. https://YOURDOMAIN:PORT/auth/facebook?code=AVERYLONGCODESENTBYFACEBOOK)
Using this code token from the query parameter, you make another API Call to get the access_token for the user
{GET}: https://graph.facebook.com/v15.0/oauth/access_token?client_id=YOUR_CLIENT_ID&redirect_uri=https://YOURDOMAIN:PORT/auth/facebook&client_secret=YOUR_CLIENT_SECRET&code=AVERYLONGCODESENTBYFACEBOOK
Facebook's API will send you an answer as JSON with the access_token inside.
You can make another call using the access token of the user, to get the userId and the username
{GET}: https://graph.facebook.com/me?access_token=ACCESS_TOKEN_SENT_BY_FACEBOOK_IN_PREVIOUS_GET_REQUEST.
If you need the e-mail address for the user you have to make another call. Make sure you'd set the permission to read the e-mail address for your app on the developer portal of facebook.
The following request will return you the id, name and the email of the user
{GET}: https://graph.facebook.com/USERIDFROMPREVIOUSREQUEST?fields=id,name,email&access_token=ACCESSTOKEN
I think you want to save all these information to a database and create a session in order to keep the user logged in and therefore all the requests described will be useful for you in a real application.
After doing all the backend stuff, you're ready for the redirection using deep link. To do that, set a meta-tag to redirect the inappbrowser to your application:
<meta http-equiv="refresh" content="0; URL={YOURAPPSDEEPLINKNAME}://{SOMEPATHYOUWANTTOEND}" />

Over-ride Browser Authentication Dialog

Is there a way using Java to over-ride the browser authentication dialog box when a 401 message is received from the web server? I want to know when this dialog is being displayed, and instead of it being given to the user, I fill in the credentials for them.
Overview of application:
i wrote the web server, so essentially i want to stop someone from opening an external browser and putting in the localhost and port to gain access to the data being displayed. my app has an embedded web browser linked to my written server. the browser displays decrypted content, so if i force the auth (even for my embedded browser), an external browser would need credentials. if my embedded browser is trying to access the files, i supply the credentials for the user and display the content
If you don't care about the password showing you can construct the URL so it passes the credentials ex. http://username:password#www.example.com This will by pass the authentication box but will show the user the credentials so also might not be what you are looking for.
SWT 3.5M6 has a new listener within it call AuthenticationListener. It simply listens for authentication event passed from the server and is fired. The code below is what performs the behavior I wanted. It waits for the auth, and if the host is my application, it passes back the credentials. Of course fill in the USER_NAME, PASSWORD and HOST_NAME with appropriate variables. Otherwise it lets the browser auth dialog pop up and makes the user enter the credentials. This code can also be found in the Eclipse SWT snippets page:
webBrowser.addAuthenticationListener(new AuthenticationListener()
{
public void authenticate(AuthenticationEvent event) {
try {
URL url = new URL(event.location);
if (url.getHost().equals(HOST_NAME))
{
event.user = USER_NAME;
event.password = PASSWORD;
}
else
{
/* do nothing, let default prompter run */
}
} catch (MalformedURLException e) {
/* should not happen, let default prompter run */
}
}
});
your question is a bit unclear. The whole basic authentication is based on HTTP Headers.
If the browser gets an authorization header than it displays the dialog. The content from the dialog is then send back to the server. There is nothing special about it. It iser username:password in base64 encoded. Have a look at
wikipedia
The problem is how you want to interfere. You would have to capture the authorization header and then for the next request you have to alter the HTTP header to include the credentials.
hope that helps
I think this is mostly browser-dependent behavior and what the server reports to the browser.
For example, Internet Explorer, being a Microsoft product, directly supports automatic sending of Windows credentials (you can modify this behavior in your Internet Settings) after an anonymous request fails in a 401.
Firefox, for example, does not and will always prompt the user even if it was set to remember the id and password via the password manager. IE will also prompt if auto-login fails (such as your Windows credentials still result in a 401 because you're id isn't allowed).
I don't think, as a web developer, you have much control over this besides setting up your server and app to work in the most expected and harmonious way... if you could, this might get into black hat territory.
If you want to control what is displayed to the user for authentication, you can change the auth-method in the login-config section of the web.xml from BASIC to FORM.
Then you can specify what page should be displayed when the user is authenticating, and, I suppose, pre-fill the credentials for them...but doesn't this defeat the whole purpose of security?
Setting up Authentication for Web Applications
Edit after further details:
My only suggestion would be to change the auth-method to CLIENT-CERT and require two-way SSL, where the client is also required to present a certificate to the server. If you install the certificate into your embedded browser (and make sure external browsers can't get the certificate) then you should be OK. And actually this should stop any authentication dialog from being displayed.