In TestCafé, I want to run a test in different browsers in parallel. Each session should sign up and log in with a different user account.
I tried to achieve this with the before hook:
let user = null;
fixture("My fixture")
.page("http://localhost:8080")
.before(() => {
user = faker.internet.email();
});
test("login", async t => {
// using user in here
});
However, this hook is just executed once for all browsers, I need to run it for each browser so that I can have different credentials each time.
Is this feasible?
This is the NPM script:
testcafe firefox,chrome,edge tests.js
Yes, you can use the beforeEach hook for this.
https://devexpress.github.io/testcafe/documentation/test-api/test-code-structure.html#test-hooks
I reconsidered this solution and think that you could use the TestCafe User Roles feature in your scenario. You can create separate roles for different browsers and then choose one of them in the beforeEach hook based on the userAgent string. Here is an example how to obtain the userAgent using a client function.
Related
I am trying to login to google with selenium and I keep getting the error that "This browser or app may not be secure."
The function I use to log in is:
async function loginToChrome(driver, username, password) {
await driver.get("https://accounts.google.com/signin");
await driver.sleep(1000);
let email_phone = await driver.findElement(
By.xpath("//input[#id='identifierId']")
);
await email_phone.sendKeys(username);
await driver.findElement(By.id("identifierNext")).click();
await driver.sleep(1000);
let passEl = await driver.findElement(By.xpath("//input[#name='password']"));
await passEl.sendKeys(password);
await driver.findElement(By.id("passwordNext")).click();
await driver.sleep(1000);
}
It is the same problem as
https://stackoverflow.com/questions/59433453/unable-to-log-into-google-account-in-selenium-chrome-driver
and
https://stackoverflow.com/questions/59276975/couldnt-sign-you-in-this-browser-or-app-may-be-insecure-python-selenium-chrome
I have tried using both the chrome and firefox web drivers and both don't work.
I have also tried doing .excludeSwitches(['enable-automation']) which also didn't help.
This made me think that maybe the sign-in page could detect that I was running in an automated environment.
I tried this solution that would hide that the app is running in a web driver: Can a website detect when you are using selenium with chromedriver?
I have also looked into the User-Agent to see if that was the problem but what I have found is that it is identical to my regular chrome one.
All of this has not worked which makes leaves me stuck. I have seen solutions that say to use an already created user profile from your normal installation of chrome, but this wouldn't work for my use case.
Has anyone found the solution to this? I have been searching for hours and have come up empty-handed.
EDIT:
It seems like this has been getting a lot of attention recently. I found a solution that allowed me to continue to use an automated client without having too many problems. Switching to Puppeteer.
Look into these packages:
"puppeteer",
"puppeteer-extra",
"puppeteer-extra-plugin-stealth"
EDIT 2:
I have seen this get a lot of attention recently. I found the code that I ended up using to login. I used puppeteer instead of selenium to do this
async function login(
page: Page,
username: string,
password: string,
backup: string
) {
await page.goto("https://accounts.google.com/");
await page.waitForNavigation();
await page.waitForSelector('input[type="email"]');
await page.click('input[type="email"]');
await page.waitForNavigation();
//TODO : change to your email
await page.type('input[type="email"]', username);
await page.waitForSelector("#identifierNext");
await page.click("#identifierNext");
await page.waitFor(1000);
await page.waitForSelector('input[type="password"]');
await page.click('input[type="password"]');
await page.waitFor(500);
//TODO : change to your password
await page.type('input[type="password"]', password);
await page.waitForSelector("#passwordNext");
await page.click("#passwordNext");
await page.waitForNavigation();
}
The followings work me as well:
1. try to login stackoverflow with your google account
2. once login, go to the email
here is solution
WebDriver driver;
System.setProperty("webdriver.chrome.driver", "chromeDriver/chromedriver.exe");
driver = new ChromeDriver();
GeneralClass te = new GeneralClass ();
driver.get("https://accounts.google.com/signin/oauth/identifier?client_id=717762328687-iludtf96g1hinl76e4lc1b9a82g457nn."
+ "apps.googleusercontent.com&as=JS6BM8cjL-8j9votansdkw&destination=https%3A%2F%2Fstackauth"
+ ".com&approval_state=!ChRoYWVvLUlNMk5hSXJWUGlaSVl2WBIfc3lSa0lueENpb29lSU5vbEVpbVNxcUZGaGNkSEJoYw%E2%88%99AJDr988AAAAAXlBKc7PzEomxSzgNqd4wLptVlf0Ny3Qx&oauthgdpr=1&xsrfsig=ChkAeAh8T8JNDxCf2Zah5fb_rQ55OMiF8KmMEg5hcHByb3ZhbF9zdGF0ZRILZGVzdGluYXRpb24SBXNvYWN1Eg9vYXV0aHJpc2t5c2NvcGU&flowName=GeneralOAuthFlow");
te.waitingForElementSendingKey(driver, By.id("identifierId"), "XXXXXXXX#gmail.com");
te.waitingForElementForClickOnly(driver, By.id("identifierNext"));
te.waitingForElementSendingKey(driver,By.name("password"), "PASSSWORD");
te.waitingForElementForClickOnly(driver, By.id("passwordNext"));
Thread.sleep(1500);
driver.get("https://mail.google.com/mail/u/0/#inbox");
Thanks
I just tried something out that worked for me after several hours of trial and error.
Adding args: ['--disable-web-security', '--user-data-dir', '--allow-running-insecure-content' ] to my config resolved the issue.
I realized later that this was not what helped me out as I tried with a different email and it didn't work. After some observations, I figured something else out and this has been tried and tested.
Using automation:
Go to https://stackoverflow.com/users/login
Select Log in with Google Strategy
Enter Google username and password
Login to Stackoverflow
Go to https://gmail.com (or whatever Google app you want to access)
After doing this consistently for like a whole day (about 24 hours), try automating your login directly to gmail (or whatever Google app you want to access) directly... I've had at least two other people do this with success.
PS - You might want to continue with the stackoverflow login until you at least get a captcha request as we all went through that phase as well.
One workaround that worked for me is creating a google account in the chrome instance started by the webdriver. Using this newly created account works for me, but I cannot tell what is exactly the difference between it and other google accounts.
Here's what worked for me:
I am using Puppeteer, but I'd bet it's the same for any automated scripts.
You must have a userDataDirectory so that the browser can use the same storage information.
You must initially run the script with headless: false so that you can get a browser to open. If you try to sign in on the current tab (the tab that was navigated automatically), then you will get that error on every sign-in attempt.
The trick (for me) was to open a new tab, navigate manually, try again.
Next time you run the script, you do not need to login.
Try using undetected_chromedriver library :
!pip install undetected_chromedriver
import undetected_chromedriver as uc
driver = uc.Chrome(executable_path='chromedriver.exe') #change for your path
driver.get('https://accounts.google.com/ServiceLogin')
#continue work code here...
It worked pretty well for me
This error message...
This browser or app may not be secure.
Try using a different browser. If you’re already using a supported browser, you can refresh your screen and try again to sign in.
...implies that the WebDriver was unable to authenticate the Browsing Context i.e. Browser session.
Potential reasons and solution
There can be diverse reason behind this error as follows:
#Raphael Schaad in the article "This browser or app may not be secure" error when trying to sign in with Google on desktop apps mentioned that, if an user can log into the same app just fine with other Google accounts, then the problem must lie with the particular account. The possible reason, it is the only account where user is using Two Factor Authentification.
Another pottential reason can be usage of Less secure apps. If an app or site doesn’t meet google-chrome's security standards, Google may block anyone who’s trying to sign in to your account from it. Less secure apps can make it easier for hackers to get in to your account, so blocking sign-ins from these apps helps keep your account safe.
Solution
In these cases the respective solution would be to:
Disable Two Factor Authentification for this Google account and execute your #Test.
Allow less secure apps
You can find a detailed discussion in Sign in to gmail account fails (selenium automation)
tl; dr
A couple of relevent documentation:
Sign in with a supported browser
Is there a way to disable or enable sign ups for a specific application which is independent of the “Disable Sign Ups”-toggle in the dashboard for login with passwordless email (Authentication/Passwordless/Email)?
Only partly.
It's possible via Pre-User-Registration Hook and/or or Rule with some caveats.
Pre-User-Registration Hooks :
https://auth0.com/docs/customize/hooks/extensibility-points/pre-user-registration
Something like this:
module.exports = function (user, context, cb) {
return cb(new PreUserRegistrationError('Denied user registration in Pre-User Registration Hook', 'You are not allowed to register.'));
}
};
Here you can just fail the registration at all times.
Problem with Hooks is that that the Pre-User-Registration Hook does not trigger for social connections / federation, only Database Connections and Passwordless.
Alternatively via Rule:
https://auth0.com/docs/customize/rules
This will always work, but the downside is that the user gets created in Auth0, they will just not be able to further proceed.
In the Rule you basically check the number of logins, if it's 0, you know that it's a new user, and block the login that follows right after user creation (signup) as well as any other time.
Example rule:
https://auth0.com/rules/disable-social-signup
Related earlier answer of mine regarding this, in the Auth0 forum:
https://community.auth0.com/t/disable-signup-from-auth0-ui-and-enable-social-login/29227/2
I just figured out I can create another 'Tenant' (from the dashboard) with a different setting for Sign Up from the dashboard :-)
You could implement a custom Universal Login SPA for sign-up/in that only allows users to sign-in. Pre-registration hook to safeguard against people bypassing the UX.
I am building an app using Nativescript-Vue that requires authentication of users in order to use the app. I have a RESTful backend that functions appropriately as tested with Postman.
JWT Tokens are implemented with a perpetual life but require refreshing every 5 minutes (refresh functionality - in a vaccuum -- working appropriately).
Using Axios.js for web calls.
I am stuck on how to implement basic logic for determining if the user is logged in. All Axios calls return a Promise. I have read the extended "Promise" responses a bunch, but it's not sinking into my head how to do what I want. In a nutshell, I need to pause code execution until the API can authenticate the user and this is not computing for me.
Code as follows:
app.js
// Import VUE library
import Vue from "nativescript-vue";
// This is my user handler
import {UserServices} from "./assets/js/UserServices.js"
// imported Components
import Login from "./components/Login";
import Home from "./components/Home.vue"
let user = new UserServices();
let loggedIn = user.checkAuthStatus();
new Vue({
render: h => h('Frame', [
h(
loggedIn ? Home : Login
)
])
}).$start();
This isn't working because user.checkAuthStatus() is an async function that returns a promise and thus I cannot get a boolean value returned. I know this is the problem, but I left that in the code so that the intended result can be understood. What I don't understand is how to rewrite the code so that the designed flow is feasible using Promises.
Core logic is designed to be:
Check the user's logged-in status via user.checkAuthStatus(). This routine checks for a valid token (valid meaning it exists and is not expired). If it is expired, the token is refreshed via a call to this.refresh() from the UserServices controller.
If a value of "true" is returned from user.checkAuthStatus() the Vue app should load the Home component (aka user is logged in), else the user should be required to login.
I can only imagine that this is a simple situation thousands of people have successfully overcome, but my brain isn't working thru it. I get why JS needs to continue running so as not to stop the progress of the code (and that's the point of a Promise, I think?), but sometimes the code just needs to stop and wait it seems, like in a user authentication scenario.
Any help drilling down on the specifics on how to address my challenge? Please and thank you.
I would do like this:
Check if a locally stored token exists, valid and not expired, if yes go to homepage else redirect to login.
Cloud functions doesn't accept onLoging by default, how can i "bypass" this limitation so i can run a cloud function every time a user gets "online".
My thought so far is to run a create document on logIn and listen to it, but what happens when the user is not login in but using his last time session?
Do i run the same post request on the isLogged function ? that function can be run many times when the application is running, so is not optimal.
is running the function on app init (angular 7) the solution here?
Only you can define what a "session" is for your app. There is no universal definition that you can use to trigger a Cloud Function. Firebase Authentication won't help with this either, since users are logged in "forever", until your code explicitly logs them out (it automatically refreshes the user's auth token every hour).
You're going to have to write your own code to figure this out by whatever specification you decide the user has "logged in" or "logged out".
You can create a function that triggers when a Firebase user is created using the functions.auth.user().onCreate() event handler:
exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
// ...
});
https://firebase.google.com/docs/functions/auth-events?hl=en-419
but one alternative you have would be , to make a write operation in the client when user login.
It is possible to disable multiple login at Keycloak?
Example:
I logged in on my browser at my PC and I do a login on my mobile phone... at this moment, keycloak invalidade the token of my other browser.
It is possible?
Update:
This feature has been implemented in keycloak version 17.
See: https://github.com/keycloak/keycloak/issues/10077
Old workaround:
Keycloak does not have this feature implemented yet. If you want you can create your own custom authenticator, for that you should have sound knowledge of keycloak codebase. I was facing the same issue and came up with a workaround.
Keycloak maintains active sessions of a user as shown below:
Every time a user logs in through different device, a session is added in the above list, we can use the above info to limit the user session to one.
I'm heavily making use of keycloak admin rest APIs to get the session-related data and to delete the session: link here
Make an API request to your server when a user logs in:
client.js
componentDidMount(){
let auth = await keycloak.init({onLoad: "check-sso"});
if(auth){
const {data} = await axios.get(`/check_session/${keycloak.subject}`);
this.setState({isSessionValid: data.isSessionValid})
}
}
render(){
return(
{this.state.isSessionValid ?
<YourComponent/> :
<div> You are already logged in!</div>
}
)
}
server.js
const baseUrl = 'http://localhost/auth';
const realm = 'myRealm'
// check session of user with same credentials from different devices
export const checkUserSession = async userId => {
// initialize access token
await initializeAccessToken(baseUrl); // check admin rest api docs of keycloak
// get all active sessions of user
const sessions = await getUserActiveSessions(baseUrl, realm, userId); // check admin rest api docs of keycloak
// check if any session exists
if (sessions && sessions.length > 1) {
// sort with start time in descending order
sessions.sort((a, b) => b.start - a.start);
const currentSession = sessions[0]; // current logged in user's session
const previousSession = sessions[1]; // previously active user's session
/* I'm preventing current user to log in, for your case you can delete
the old session of this user here */
await deleteUserSession(baseUrl, realm, currentSession.id); // check admin rest api docs of keycloak
return { isSessionValid: false, sessionData:previousSession };
}
// user logged in first time
return { isSessionValid: true };
};
Looks like a lot of Keycloak users are interested in this feature so I am posting an answer which I found on my conducted research, this feature implemented by unofficial developer and here is what he shared
You can get the authenticators from my cloned branch:
https://github.com/mfdewit/keycloak/tree/KEYCLOAK-849-configurable-session-limits/services/src/main/java/org/keycloak/authentication/authenticators/sessionlimits
I've created 2 authenticators:
`RealmSessionLimitsAuthenticator`: limits the total number of sessions for a realm.
`UserSessionLimitsAuthenticator`: limits the number of session per user account and per client.
For now I advise you to copy them (including the factories) to your own project and make sure they are referenced in META-INF/services.
Also, change the AuthenticationFlowError.SESSION_LIMIT_EXCEEDED error to some value that exists in your Keycloak version. SESSION_LIMIT_EXCEEDED is added by me and only exists on my feature branch.
The downside is that you cannot provide the user proper feedback in case his session is denied.
If you have any questions on how these should be used, let me know!
Regarding the status of this task: I still have to write the integration tests before I can submit the merge request. But I'm planning to finish this soon. If anyone want to help writing these tests, I'd be grateful.
Still keycloak official JIRA i didn't find if they incorporated this feature in any recent version of Keycloak
Source
https://github.com/mfdewit/keycloak/tree/KEYCLOAK-849-configurable-session-limits/services/src/main/java/org/keycloak/authentication/authenticators/sessionlimits
These feature has been implemented in keycloak 17 : https://github.com/keycloak/keycloak/issues/10077