HTTP authenticating --- some weird way - javascript

When I try to login emodal.com (I assume it uses basic authentication because it just requires a user/pass) on the browser it works fine and lets me go to a certain page and lets me through. However when I try to go in the page that I want and authenticate programmatically (using request or request-promise) it gets denied because of "invalid credentials". It seems like I need to login manually through a browser or something by clicking the login button and THEN i would be able to go to the private protected page that I want (why doesn't it work programmatically whereas the browser (google chrome) works? Is it going through a second step in the authentication process that I am not aware of?)
Here I provided 3 screenshots of how the devtools console looks when I log in (it makes a request to ValidateWharfageUser, then Login, then GetStatus as shown, then I guess thats where it denies me programmatically).
import dotenv = require('dotenv');
dotenv.config({ path: '../logins.env' });
import rp = require('request-promise');
const jsonUrl = `http://availability.emodal.com/ImportAvailability/GetContainerInfoList?sgrdModel=%7B%22searchtext%22:%22%22,%22page%22:1,%22pageSize%22:280,%22sortBy%22:%221%22,%22sortDirection%22:%22asc%22,%22sortColumns%22:%22%22%7D`;
const authOpts = {
uri: jsonUrl,
auth: {
user: process.env.EMODAL_id,
pass: process.env.EMODAL_pw,
sendImmediately: false
},
method: 'get'
}
rp(authOpts)
.then(resp => {
console.log(resp);
}).catch(err => { throw Error(err)});
The 3 screenshots:
http://i.imgur.com/hjThLt1.png
http://i.imgur.com/0uPAMMs.png
http://i.imgur.com/xBF2DAV.png

Related

Next.js redirect from an API route

I am building a back-office app that requires users to sign in.
I have 2 external APIs:
API A : to manage user accounts and sessions
API B : to perform CRUD actions on another database (unrelated to users database)
The problem is that I don't want users to be able to perform calls to API B if their session is not valid. So I added some API endpoints in Next (under pages/api) that do the following actions:
verifying the validity of the session against API A
if session is valid: continue to step 3, if not: redirect to page /login
make the call to API B
Everything works fine if the session is valid but it fails if the session is not valid.
I have tried
res.redirect(307, '/login').end()
and
res.writeHead(307, { Location: '/login' }).end()
but it didn't work. It fails even by specifying the whole path (http://localhost:3000/login). What I don't understand is that I am successfully redirected to my /login page if I make the request directly from the browser (GET http://localhost:3000/api/data). It doesn't work when I make the request with Axios inside a React component.
Any idea how I can fix this?
As #juliomalves and #yqlim explained, I had to make the redirect manually based on the response of the API.
Faced same problem solve using below code:
Api
res.status(200).json({ success: "success" }) //add at last of the api to give response
page
import Router from 'next/router'
let res = await fetch('api', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
if (res.status == 200) {
Router.push('/location')
}
Answer is correct as #Jules Grenier sayes,but provided an example
You do not need .end(). Have you tried res.redirect(307, '/login')?
In Next.js v12 and v13, the following works for me.
// /api/example.js
const handler = async function (req, res) {
// custom logic
if (failed)
return res.redirect(307, '/login')
}
export default handler;
The API request must be initiated by a <form>.
redirect will not work with <fetch>

I don't want to send form data back with express, but it does, or does it?

I know the title of this question might sound confusing, but my problem is actually simple. I have these two handlers for /login get and post requests:
loginRender(req, res) {
let options = { title: 'Login', layout: 'auth.hbs' }
res.render('login', options)
}
login (req,res){
let user = Routes.findUser(req.body.username)
let passwordCorrect = Routes.hashCompare(
req.body.password,
user.password
)
if (passwordCorrect) {
let token = Routes.jwtsign(req.body.username)
let refreshToken = Routes.jwtRefreshToken(req.body.username)
Routes.authRedirect(res, token, refreshToken)
} else {
Routes.badRequestRedirect(res, '/login')
}
}
authRedirect(res, token, refreshToken )
{
let options = {
cssPath: 'styles/querystyle.css',
}
res.cookie('access_token', `${token}`, { httpOnly: true })
res.cookie('refresh_token', `${refreshToken}`, { httpOnly: true })
res.status(200).render('query', options)
}
// app.use(urlencoded)
// app.use(cookieParser)
// app.post('/login', login)';
// app.get('/login', loginRender)
Please, ignore all unrelated stuff.
So, everytime I complete login, I get my webpage rendered and I can actually open inspector and see this:
Page Inspector
Address line
How can I fix that? I want my user to be redirected to dashboard-like page and not to receive his sensitive data in insecure form.
UPD
there's also auth middleware that only appends req.username in case we did parse jwt successfully, and there's a little bit of interaction with it, but it does not appear on page until I go to this page manually by writing the address in address line.
If you don't send the data to the Express server, then you can't read it in you login function and you can't authenticate the user.
It is not a problem is the user can use the tools in their own browser to inspect the data that they entered.
You need it to be encrypted in transport (i.e. use HTTPS and not plain HTTP, at least in production) but you don't need to worry about the user finding out their own password.

TestCafe: How to test logout if user logged in from another machine

I have a scenario where I want to start running a test on chrome and at specific point I want my test to open different browser (firefox) and to do the same steps as in chrome then go back to chrome again and verify a change in ui. Is there anyway to do this using testcafe?
I am glad I asked.
In order to test if a login in another browser triggers a logout in the current browser, there is no need to run a different browser.
You can send the according login command from your test code.
node.js builtin standard http library is sufficient for that task. The official documentation has a specific section on http requests: https://nodejs.org/en/knowledge/HTTP/clients/how-to-create-a-HTTP-request/
I personally prefer the fetch API as available in the browser. node-fetch provides this API in node.
so your test code could look a little like this:
import 'node-fetch';
import { URLSearchParams } from 'url';
// we assume we get page state and interaction from this seperate module
import { loginAction, getIsLogged } from './page-actions';
fixture `login logut`
.page `http://your.app/`;
test('User is logged out if logged in somewhere else', async t => {
// perform the login actions to login as "username"
await loginAction(t, 'yourUsername', 'yourPassword');
await simulateLoginFromSomewhereElse('yourUsername', 'yourPassword');
await t.expect(getIsLoggedIn(t)).eql(false);
});
async function simulateLoginFromSomewhereElse(username, password) {
// build the (form) data to be sent to the server
const params = new URLSearchParams();
params.append('username', 'yourUsername');
params.append('password', 'yourPassword');
await fetch(`http://your.app/login`, { method: 'POST', body: params });
}

302 redirects do not work in a service worker built with Google Workbox

For having the "add tome homescreen" alert displayed, I want to integrate a service-worker and an offline capability of the application: When the user is offline, the app should simply display a special offline HTML file.
My service-worker looks like this:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.1.0/workbox-sw.js');
const CACHE_VERSION = 1;
workbox.core.setCacheNameDetails({
prefix: 'app',
suffix: 'v' + CACHE_VERSION
});
workbox.routing.registerRoute(
'/offline-page.html',
workbox.strategies.networkFirst({
networkTimeoutSeconds: 2,
cacheableResponse: { statuses: [0, 200] },
})
)
workbox.routing.registerRoute(
({ event }) => event.request.mode === 'navigate',
({ url }) =>
fetch(url.href, { credentials: 'include', redirect: 'follow', }).catch(() => caches.match('/offline-page.html'))
)
But as soon as my application returns a 302 redirect (e.g. after login oder logout), I get the following warning message in the console:
The FetchEvent for "https://app.com" resulted in a network error response: a redirected response was used for a request whose redirect mode is not "follow".
and Google Chrome diplays an error page (ERR_FAILED) saying that the website can't be reached.
Does anyone have an idea how to fix this?
You can adapt the "Provide a fallback response to a route" recipe in the docs to accommodate your particular restrictions.
There are a couple of different options for accomplishing this, but the cleanest would be to create your own network-only strategy (to mimic the fetch() that you're using in your example), chain .catch() to the end of it, and then use that as the handler when constructing a NavigationRoute.
That will give you a Route that you could then pass to workbox.routing.registerRoute().
// You're responsible for either precaching or
// explicitly adding OFFLINE_HTML to one of the caches.
const OFFLINE_HTML = '/offline-page.html';
const networkOnly = workbox.strategies.networkOnly();
const networkOnlyWithFallback = networkOnly().catch(() => caches.match(OFFLINE_HTML));
const route = new workbox.routing.NavigationRoute(networkOnlyWithFallback);
workbox.routing.registerRoute(route);
This seems to do the trick:
const FALLBACK_URL = '/';
const networkOnly = workbox.strategies.networkOnly();
const route = new workbox.routing.NavigationRoute(({event}) => {
return networkOnly.handle({event})
.catch(() => caches.match(FALLBACK_URL));
});
workbox.routing.registerRoute(route);

How to create a function to get an Auth0 token

I’m trying to create a function to get a login token from Auth0 for a user for so I don’t have to use the login test before every test scenario (which isn’t working anyway), but rather I want to have a stored token and use that to authenticate the user so I can test the application.
I’m not a developer (or even a developer in Test). I’m a QA who is trying to learn enough Javascript in order to use Cypress to create test scenarios for our new internal risk assessment application.
We have a list of users for our new app which will all be verified through Auth0. All the users are internal to our company and are based on our emails which are linked to Microsoft accounts.
Below is my login test that presses the login button, which is then redirected to Auth0 and then enters my email address to verify the login. This is successful except for the fact that it doesn’t actually load the application.
```
describe('My Login Test', function (){
it('Visit Risk App Landing Page', function (){
const typedText = 'adam.allford#landmark.co.uk'
cy.visit('https://bvt-riskassessment.lmkcloud.net')
cy.get('button').click()
cy.get('input.auth0-lock-input').first()
.type(typedText)
.should('have.value', typedText)
cy.get('button').click()
cy.url().should('eq','http://bvt-riskassessment.lmkcloud.net/workflow')
})
})
```
I had a reply on a Gitter forum from someone who had a similar issue and used what is displayed below (or similar) to try and login. I edited it with relevant details for what I need and put this in the command.js with a loginuser.json (containing username and password) in the shown loacation, and then included the beforeEach in a test scenario.
```
Cypress.Commands.add('login', (userType, options = {}) =>
{cy.readFile(`cypress/fixtures/loginUser.json`).then((json) => {
const { email, password } = json
const dataToSend = {
email,
password,
}
cy.request({
url: `https://lmcorp.eu.auth0.com/userinfo`,
method: 'POST',
body: dataToSend,
form: true
}).then((response) => {
const { status, body } = response
expect(status).to.eq(200)
expect(body).to.have.property('success', 1)
cy.visit(url)
})
})
//and use it like :
beforeEach(() => { login('url') })
```
… and then included the beforeEach in a test scenario.
```
describe('My First Test', function (){
it('Visit Risk App Landing Page', function (){
beforeEach(() => { login('https://lmcorp.eu.auth0.com/')})
cy.visit('http://localhost:3000/workflow')
cy.contains('Site Solutions Combined Assessments')
cy.contains('To Do')
cy.contains('Assessing')
cy.contains('Reviewing')
cy.contains('Done')
cy.get('button').click()
cy.contains('Assessments')
cy.contains('Site Solutions Combined')
cy.contains('Flood')
cy.contains('Whatever Next')
})
})
```
But I get the following message on the command console.
![alt]https://i.imgur.com/cJljZzm.png
I’m completely stuck and don’t know where to go from here. My question is: I want to create a feature that will call our Auth0 url and get a login authentication token, which can be used to allow access the application for every test scenario. Can I change what I have here to make that work, or does anyone have any suggestions on how to create a new feature to get an Auth0 token?

Categories