Selenium web driver scripts for Authenticated view - selenium-webdriver

I am new for Automation testing using selenium web driver for chrome.I want to test authenticated view from selenium web driver ,so i wrote code
public void WriteReviewAfterLogin()
{string BaseUrl = "http://vps65937-6.lcnservers.com/10300/profile/login.php";
var driver = new ChromeDriver();
driver.Navigate().GoToUrl(BaseUrl);
var loginBox = driver.FindElement(By.Id("username"));
loginBox.SendKeys("govinda.silverlight#gmail.com");
var pwBox = driver.FindElement(By.Id("password"));
pwBox.SendKeys("12345");
var signinBtn = driver.FindElement(By.CssSelector("[class='btn btn-default signin']"));
signinBtn.Click();
const string url = "http://vps65937-6.lcnservers.com/10300/company-reviews/sks-security-53beee89163ce.html";
driver.Navigate().GoToUrl(url);
((IJavaScriptExecutor)driver).ExecuteScript("window.resizeTo(1024, 768);");
var reviewTitle = driver.FindElement(By.Id("review_title"));
reviewTitle.SendKeys("thi is testing titile");
var review = driver.FindElement(By.Id("review"));
review.SendKeys("this is testing");
var signinBtns = driver.FindElement(By.CssSelector("[class='submitReview']"));
signinBtns.Click();
driver.Navigate().GoToUrl("http://vps65937-6.lcnservers.com/10300/");
}
invoked as
private static void Main(string[] args)
{
SeliniumChrome loginSeliniumChrome=new SeliniumChrome();
loginSeliniumChrome.WriteReviewAfterLogin();
}
When this code runs the login view is authenticated and redirected to another url,the login state is lost how to set in log in state in that case.

I don't find any use of below mentioned lines in your code. Better to remove these lines because once you will login you will be redirected to below mentioned url.
const string url = "http://vps65937-6.lcnservers.com/10300/company-reviews/sks-security-53beee89163ce.html";
driver.Navigate().GoToUrl(url);

Related

Blazor WASM - Multiple Authentication Schemes (Azure AD and B2C)

I am trying to implement multiple authentication schemes in Blazor WASM. I want my users to be able to login using either Azure AD or Azure B2C and I don't want to use Custom User Flows in Azure B2C as I have found that to be very complex and error-prone to configure. I would like to have 2 x Login buttons ie. Login AD and Login B2C.
Each button on its own is simple to implement using MSAL, but I am struggling to get both working. In Microsoft.Web.Identity, we have the option of defining multiple Authentication Schemes. However, I don't see anything like that in WASM / MSAL.
I have been working on the following concept adjusting the authentication urls for each scheme.
LoginDisplay.razor
#using Microsoft.AspNetCore.Components.Authorization
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
#inject NavigationManager Navigation
<AuthorizeView>
<Authorized>
Hello, #context.User.Identity?.Name!
<button class="nav-link btn btn-link" #onclick="BeginLogOut">Log out</button>
</Authorized>
<NotAuthorized>
Log in AD
Log in B2C
</NotAuthorized>
</AuthorizeView>
#code{
public void BeginLogOut()
{
Navigation.NavigateToLogout("authenticationAD/logout");
}
}
AuthenticationAD.razor
#page "/authenticationAD/{action}" /*NOTE Adjusted url*/
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="#Action" >
</RemoteAuthenticatorView>
#code{
[Parameter] public string? Action { get; set; }
}
AuthenticationB2C.razor
#page "/authenticationB2C/{action}" /*NOTE Adjusted url*/
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="#Action" >
</RemoteAuthenticatorView>
#code{
[Parameter] public string? Action { get; set; }
}
Program.cs
var builder = WebAssemblyHostBuilder.CreateDefault(args);
............
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureB2C", options.ProviderOptions.Authentication);
options.ProviderOptions.Authentication.PostLogoutRedirectUri = "authenticationB2C/logout-callback";
options.ProviderOptions.Authentication.RedirectUri = "authenticationB2C/login-callback";
var webApiScopes = builder.Configuration["AzureB2C:WebApiScopes"];
var webApiScopesArr = webApiScopes.Split(" ");
foreach (var scope in webApiScopesArr)
{
options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
}
var appPaths = options.AuthenticationPaths;
appPaths.LogInCallbackPath = "authenticationB2C/login-callback";
appPaths.LogInFailedPath = "authenticationB2C/login-failed";
appPaths.LogInPath = "authenticationB2C/login";
appPaths.LogOutCallbackPath = "authenticationB2C/logout-callback";
appPaths.LogOutFailedPath = "authenticationB2C/logout-failed";
appPaths.LogOutPath = "authenticationB2C/logout";
appPaths.LogOutSucceededPath = "authenticationB2C/logged-out";
appPaths.ProfilePath = "authenticationB2C/profile";
appPaths.RegisterPath = "authenticationB2C/register";
});
builder.Services.AddOidcAuthentication(options => //THIS CODE DOES NOT RUN
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions);
options.ProviderOptions.PostLogoutRedirectUri = "authenticationAD/logout-callback";
options.ProviderOptions.RedirectUri = "authenticationAD/login-callback";
options.ProviderOptions.ResponseType = "code";
var webApiScopes = builder.Configuration["AzureAd:WebApiScopes"];
var webApiScopesArr = webApiScopes.Split(" ");
foreach (var scope in webApiScopesArr)
{
options.ProviderOptions.DefaultScopes.Add(scope);
}
var appPaths = options.AuthenticationPaths;
appPaths.LogInCallbackPath = "authenticationAD/login-callback";
appPaths.LogInFailedPath = "authenticationAD/login-failed";
appPaths.LogInPath = "authenticationAD/login";
appPaths.LogOutCallbackPath = "authenticationAD/logout-callback";
appPaths.LogOutFailedPath = "authenticationAD/logout-failed";
appPaths.LogOutPath = "authenticationAD/logout";
appPaths.LogOutSucceededPath = "authenticationAD/logged-out";
appPaths.ProfilePath = "authenticationAD/profile";
appPaths.RegisterPath = "authenticationAD/register";
});
await builder.Build().RunAsync();
This works as far as pressing the Login Button routes me to the correct authenticationXX.razor view.
The issue that I'm facing is that the second .AddXXXAuthentication does not run, so the OAuth settings for the second statement are not set. If I change the order, it is always the second statement that doesn't run. Authentication works fine based upon the first statement.
I tried using 2 off .AddMSALAuthentication statements and in that case, both statements did run. However, the ProviderOptions from appsettings.json were just over-written in the second statement. ie. it didn't create two instances of the MSAL Authentication scheme.
I know that I can hand-craft the url strings for each of the oauth steps using tags in the < RemoteAuthenticationView > component, but I was hoping to find a way to use native libraries where-ever possible to reduce the risk of introducing a security weakness in my application.
Has anyone else had experience with this scenario and can point me to some documentation / an example of how it can be done?

Correct Flow for Google OAuth2 with PKCE through Client App to SAAS API Server

So we are working on a client application in Windows WPF. We want to include Google as a login option and intend to go straight to the current most secure method. At the moment we have spawned a web browser with the following methods to obtain a Authorization Code
private async void HandleGoogleLogin() {
State.Token = null;
var scopes = new string[] { "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "openid" };
var request = GoogleOAuthRequest.BuildLoopbackRequest(scopes);
var listener = new HttpListener();
listener.Prefixes.Add(request.RedirectUri);
listener.Start();
// note: add a reference to System.Windows.Presentation and a 'using System.Windows.Threading' for this to compile
await Dispatcher.Invoke(async () => {
googleLoginBrowser.Address = request.AuthorizationRequestUri;
});
// here, we'll wait for redirection from our hosted webbrowser
var context = await listener.GetContextAsync();
// browser has navigated to our small http servern answer anything here
string html = string.Format("<html><body></body></html>");
var buffer = Encoding.UTF8.GetBytes(html);
context.Response.ContentLength64 = buffer.Length;
var stream = context.Response.OutputStream;
var responseTask = stream.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
{
stream.Close();
listener.Stop();
});
string error = context.Request.QueryString["error"];
if (error != null)
return;
string state = context.Request.QueryString["state"];
if (state != request.State)
return;
string code = context.Request.QueryString["code"];
await APIController.GoogleLogin(request, code, (success, resultObject) => {
if (!success) {
//Handle all request errors (username already exists, email already exists, etc)
} else {
((App)Application.Current).UserSettings.Email = resultObject["email"].ToString();
((App)Application.Current).SaveSettings();
}
attemptingLogin = false;
});
}
and
public static GoogleOAuthRequest BuildLoopbackRequest(params string[] scopes) {
var request = new GoogleOAuthRequest {
CodeVerifier = RandomDataBase64Url(32),
Scopes = scopes
};
string codeChallenge = Base64UrlEncodeNoPadding(Sha256(request.CodeVerifier));
const string codeChallengeMethod = "S256";
string scope = BuildScopes(scopes);
request.RedirectUri = string.Format("http://{0}:{1}/", IPAddress.Loopback, GetRandomUnusedPort());
request.State = RandomDataBase64Url(32);
request.AuthorizationRequestUri = string.Format("{0}?response_type=code&scope=openid%20profile{6}&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
AuthorizationEndpoint,
Uri.EscapeDataString(request.RedirectUri),
ClientId,
request.State,
codeChallenge,
codeChallengeMethod,
scope);
return request;
}
To my understanding, from this point the client app has completed the required portion to have the user login to their google account and approve any additional privileges.
Our API/App server is in GoLang.
APIController.GoogleLogin
from above sends the CodeVerifier and AuthorizationCode to the GoLang application server to then finish off the OAuth2 Flow.
Is this the correct flow given our client-server setup?
If so, what is the best practice for the Go Server to retrieve a Access Token/Refresh Token and get user information? Should the client app be performing a looping check-in to the app server as the app server will not immediately have the required information to login?
Thanks for the help!

Failed to connect to localhost/127.0.0.1:44326

I'm facing this error when I've to fetch data from web API from localhost, android app is running in emulator.
Failed to connect to localhost/127.0.0.1:44326
No response is getting from the localhost server in xamarin app whereas I'm able to fetch result in postman and in browser as well. I put URL ("https://localhost:44326/api/passportStatus") in xamarin MainPage.xaml.cs. are these info sufficient to know what I want actually?
This is my mainpage.xaml.cs
public partial class MainPage : ContentPage
{`public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
empDetails();
}
private async void empDetails()
{
var result = "";
HttpClient client = new HttpClient();
var API_URL = "https://localhost:44326/api/passportStatus";
client.BaseAddress = new Uri(API_URL);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage respons = await client.GetAsync(API_URL);
result = await respons.Content.ReadAsStringAsync();
var PassportDetails = JsonConvert.DeserializeObject<List<detail>>(result);
EmpDeatils.ItemsSource = PassportDetails;
}
}
check whether you have installed nuget package conveyor,if it is ok edit API URL as follows http://192.168.8.200:45455/ in yours question add 44326 insted of 45455
Update your code like below
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
empDetails();
}
private async void empDetails()
{
var result = "";
HttpClient client = new HttpClient();
var API_URL = "https://192.168.0.47:44326/api/";//Updated
client.BaseAddress = new Uri(API_URL);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage respons = await client.GetAsync("passportStatus");//Updated
result = await respons.Content.ReadAsStringAsync();
var PassportDetails = JsonConvert.DeserializeObject<List<detail>>(result);
EmpDeatils.ItemsSource = PassportDetails;
}
}
Hope this will resolve ur issue
127.0.0.1 is localhost; it's the IP address of every local machine,
that means you try to create a request from an Android App to an Android device
In another word, you try to connect with an Android device, not with a computer Localhost.
for that, you need to change the localhost in the computer from 127.0.0.1 to the current IP4 of your computer.
now try this extension and follow the instructions to do that in Visual studio:
https://marketplace.visualstudio.com/items?itemName=vs-publisher-1448185.ConveyorbyKeyoti

Authorization code flow with Identitity4 and OidcClient

For a Winforms Desktop application I will use the authorization code flow with PKCE. As Identity provider I use IdentityServer and as client library OicdClient.
Next step I have to decide which Browser to use for the user login:
SystemBrowser
Extended WebBrowser
For SystemBrowser speaks the simple/clear implementation of the flow.
For Extended WebBrowser speaks that some user may have no SystemBrowser. But the WebBrowser is an older IE version? and is it allowed to use for a secure authentication?
Nevertheless I tried the "Extended WebBrowser" Sample and stumble integrating it in to my prototype Environment with own IS4 server. Therefore I need some clarity with the code flow and redirect.
I already had implemented this authorization code flow with pure .Net classes, but using OicdClient makes me little confusing(in the beginning like a black box).
My question is how does the redirect work with this libraries and who are responsible for redirect and who are responsible to receive the redirect with the code (to exchange for access token)?
The code flow has following steps (without details like clientID, PKCE ...):
Send a code request to IS4
IS4 Response with a login page (shown in a Browser)
After successful login IS4 sends to redirect URL with code
A HttpListener receives this redirect with code and
Send a request to IS4 with the code to receive a access token
With OidcClient and using the Automatic Mode:
var options = new OidcClientOptions
{
Authority = "https://demo.identityserver.io",
ClientId = "native",
RedirectUri = redirectUri,
Scope = "openid profile api",
Browser = new SystemBrowser()
};
var client = new OidcClient(options);
var result = await client.LoginAsync();
Here is to much magic for me. Only a call to LoginAsync() makes it work...
An important point seems to be the Browser property of the options with the IBrowser interface and its implementation of this method:
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken)
{
using (var listener = new LoopbackHttpListener(Port, _path))
{
OpenBrowser(options.StartUrl);
try
{
var result = await listener.WaitForCallbackAsync();
if (String.IsNullOrWhiteSpace(result))
{
return new BrowserResult { ResultType = BrowserResultType.UnknownError, Error = "Empty response." };
}
return new BrowserResult { Response = result, ResultType = BrowserResultType.Success };
}
catch (TaskCanceledException ex)
{ ....}
}
}
if I try to map to the flow steps:
Login page: OpenBrowser(options.StartUrl);
Redirect will be done by IS4? The SystemBrowser from sample does not do this.
Receive the code: await listener.WaitForCallbackAsync();
1 and 5 are probably done by the OicdClient. This Example is fairly clear, need confimation that redirect is done by IS4.
The implementation in the other example Extended WebBrowser
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default(CancellationToken))
{
using (var form = _formFactory.Invoke())
using (var browser = new ExtendedWebBrowser()
{
Dock = DockStyle.Fill
})
{
var signal = new SemaphoreSlim(0, 1);
var result = new BrowserResult
{
ResultType = BrowserResultType.UserCancel
};
form.FormClosed += (o, e) =>
{
signal.Release();
};
browser.NavigateError += (o, e) =>
{
e.Cancel = true;
if (e.Url.StartsWith(options.EndUrl))
{
result.ResultType = BrowserResultType.Success;
result.Response = e.Url;
}
else
{
result.ResultType = BrowserResultType.HttpError;
result.Error = e.StatusCode.ToString();
}
signal.Release();
};
browser.BeforeNavigate2 += (o, e) =>
{
var b = e.Url.StartsWith(options.EndUrl);
if (b)
{
e.Cancel = true;
result.ResultType = BrowserResultType.Success;
result.Response = e.Url;
signal.Release();
}
};
form.Controls.Add(browser);
browser.Show();
System.Threading.Timer timer = null;
form.Show();
browser.Navigate(options.StartUrl);
await signal.WaitAsync();
if (timer != null) timer.Change(Timeout.Infinite, Timeout.Infinite);
form.Hide();
browser.Hide();
return result;
}
}
Done by: browser.Navigate(options.StartUrl);
Redirect by IS4
Receive of code in event handle: NavigateError ???
Is here something wrong?
On IS4 the AccountController.Login is called
that calls /connect/authorize/callback? with the redirect_uri.
But this doesn't come to BeforeNavigate2. instead NavigateError event appears where the result set to:
result.ResultType = BrowserResultType.Success;
result.Response = e.Url;
Current best practice is to use the user's default web browser and not to embed a browser component. As for how to implement that - since you can't intercept browser navigation events using this approach you'd need to implement an HTTP listener that can accept the POST request from your identityserver4 implementation.
Have a read of this: https://auth0.com/blog/oauth-2-best-practices-for-native-apps/
And this RFC: https://www.rfc-editor.org/rfc/rfc8252

Authentication Window Alert is working in IE11 but not working in Chrome v60

In my scenario, when I launch a URL, an authentication alert window opens up and I need to enter Username and Password from excel and on clicking on 'Log In' it'll show me the web homepage. I've implemented this using the below code snippet and it's working perfectly in IE11. But when I'm trying to run the same code in Chrome v60, it's not working. It's showing the authentication alert window but not performing any action on it. Screenshot attached. Can anyone suggest please.
Selenium WD version - 3.4.0
Code:
public static void loadApplicationURL(WebDriver driver) throws Exception
{
String SSPathl = null;
String URL = Generic_Functions.GetParameterFromInputSheet("URL");
try
{
driver.get(URL);
Thread.sleep(6000);
LoginApplication.isAlertPresent(driver);
}
}
public static boolean isAlertPresent(WebDriver driver) {
try {
driver.switchTo().alert();
UserAndPassword UP = new UserAndPassword(UserName,Password);
driver.switchTo().alert().authenticateUsing(UP);
Thread.sleep(8000);
return true;
}
catch (Exception e) {
return false;
}
}
For test browsers, have created a separate class. Find below the snippet used for IE and Chrome browsers.
For Chrome
System.setProperty("webdriver.chrome.driver",".\\Resources\\chromedriver.exe");
driver = new ChromeDriver()
In case of IE,
[System.setProperty("webdriver.ie.driver",".\\Resources\\IEDriverServer.exe");
DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();
ieCapabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,true);
ieCapabilities.setCapability("nativeEvents", true);
driver = new InternetExplorerDriver(ieCapabilities);][1]

Resources