Using Selenium to authenticate SAML through redirects - c#

I am working on Selenium testing for a project that is accessed via JSP which uses SAML to authenticate the user. I cannot find a way to provide credentials through to the SAML page, which is accessed through a 302 redirect.
I want to log in to home.domain.com/run.jsp. When I visit the page, I get a 302 redirect to auth.domain.com/adfs/ls/wia?SAMLRequest=<long_token>, where I fill in the browser's dialog window with my credentials. After submitting them, I am redirected back to home.domain.com/run.jsp, but with access this time.
The common Selenium auth answer seems to be adding the credentials to the url (admin:passw0rd#home.domain.com/run.jsp), but that doesn't pass the credentials through the redirect, and I even get a warning: You are about to log in to the site "home.domain.com" with the username "admin", but the website dos not require authentication. This may be an attempt to trick you.

My workaround for this ended up waiting for the redirect, then add the credentials to the current url and re-load the authentication page. If somebody has a better answer, I'd accept it because this is definitely hacky.
driver.Navigate().GoToUrl("home.domain.com/run.jsp");
Thread.Sleep(1000); // wait for redirects
// if the SAML didn't automatically authenticate and return us to the homepage
if (driver.Url.Contains("SAMLRequest")
{
driver.Navigate().GoToUrl(driver.Url.Replace("://", "://admin:passw0rd#"));
}

Related

Issue in accessing one site from another site through limited access URL

I have two websites, both in separate domains. So for e.g. http://example1.com and http://example2.com. Both sites are in ASP .NET and use Forms authentication. Users of example1.com need to access certain resources of example2.com without needing to have accounts in example2.com. So whenever a user of example1.com needs to access a resource in example2.com, a temporary URL is generated through which the user can access the resource. The URL is a limited period one time use URL that is invalidated after first time use. Here is how it works.
When example1.com needs to access resource on example2.com side, a response.redirect occurs with an encrypted token in the query string. e.g. http://example2.com/path/resource1/?token=encryptedToken
This token is read on example2.com side and if it is valid, forms authentication is set to "temp user". "Temp User" is a limited access user created specifically as a proxy for example.com users.
Below is the code to achieve this in Application_AuthenticateRequest event
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
const string TempUser = "TempUser";
if (!Request.IsAuthenticated)
{
var url = Request.Url;
var token = Request.QueryString["token"];
if(IsKnownUrl(url) && IsValidToken(token))
{
FormsAuthentication.SetAuthCookie(TempUser, false);
Response.Redirect(Request.RawUrl);
}
}
}
private bool IsKnownUrl(string url){
//Logic to check the url is from known sources
}
private bool IsValidToken(string token){
//Logic to token is valid and not expired
}
This was working fine until both sites were switched to SSL. i.e. https://example1.com and https://example2.com. and this stopped working. The Response.Redirect from example1.com to example2.com goes into a 302 loop, which means for some reason the authentication cookie is not being set or accepted. When I view the network activity in Chrome Browser Developer tools, I see following trail
Name Status
https://example2.com/path/resource1/?token=encryptedToken 302
https://example2.com/path/resource1/?token=encryptedToken 302
https://example2.com/path/resource1/?token=encryptedToken 302
..................
Finally the Browser gives up and indicates the page is redirecting too many times.
Any ideas on what could be wrong?
Thanks Aydin for your tip. For anyone who is also facing similar issue, here is the solution.
After checking with Fiddler, I found that Authentication cookies (.ASPXAUTH) were being sent from the server but the browser was not sending them on subsequent requests.
Also, the URLs from example2.com were being displayed in example1.com inside an IFrame. After some searching I found that for IFrames, the browser will send cookies only if "SameSite=None" is specified in the Set-Cookie response header.
So in the end I had to update my code to create the ASPXAUTH cookie manually since the cookie created by FormsAuthentication class sets its to "Lax".

AWS Cognito built-in sign in redirection issue

I am trying to incorporate Cognito built-in sign in logic into our workflow.
Here is scenario I try put to work:
I need redirect to specific URI after successful signing in through Cognito built-in UI of the user, which has been created in the User Pool. But I do not understand how to do it.
I've created User Pool, app client, configured domain, provided callback url, created a user.
I configured "Allowed OAuth Flows" to useAuthorization code grant "Allowed OAuth Scopes" is set to openid
So far - so good.
Then I came up following URL to conjure up Cognito built-in UI:
https://<my-domain>.amazoncognito.com/authorize?response_type=code&client_id=<my-client-id>&redirect_uri=https://<my-domain>.amazoncognito.com/login?client_id=<my-client-id>
Upon executing it in a browser of my choice I am hitting Cognito built-in sign in page. But upon clicking "Sign in" button I've got an error: Required String parameter 'redirect_uri' is not present
Ok, I thought to myself, let's add redirect_uri attribute at the end of the aforementioned URL and path would be cleared to success, but such optimism has been short lived. I've got dreaded: "redirect_mismatch" error. I've tried to provide multiple callback urls, but with no success. redirect_mismatch error blocking my way.
And now I have no idea how to instruct Cognito to redirect to desired url. Any ideas are welcome.
You shouldn't set the 'redirect_uri' to Cognito's Login Endpoint. It makes no sense. The 'redirect_uri' is a parameter to tell Cognito where to take the user after login, which would be your application's url.
The 'redirect_uri' should exactly match one of the Callback URIs for the app client you configured for security reasons, otherwise you will get a' redirect_mismatch' error.
To access the login endpoint:
https://mydomain.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI
For the authorize endpoint:
https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI
The authorize endpoint firsts checks to see if you have a session cookie indicating that you're already logged in, and if you are, it automatically redirects you to the redirect_uri, otherwise it will take you to the login page via the Login Endpoint with the query strings provided to the authorize endpoint.

Is there a built in way to have ASP.NET accept posted data with GET instead of POST?

We have a straight forward ASP.NET web application with a login page. After the user enters credentials and submits the form, the server processes the details and if successful, Response.Redirect()'s the user to the Main Menu page. (We also have a navigation bar where the user can navigate to other pages via similar response.redirects)
One of our customers is setting up an IBM Data Power Web Application Firewall, and has told us this Redirect after a POST is an RFC violation and consequently the application does not work.
There are a few questions here that are related to Get/Post/Redirect, and they indicate that its up to the discretion of the browser to use the 302 response as a get or a post. I have also found other links on the public internet that lead me to believe this something the IBM device could be configured to handle.
Before I suggest changing the IBM device configuration, are there any configuration based (or simple code) ways to make a trivial login page (not using the asp.net login control) work where a GET request can send the login credentials, or make all postbacks in the site use a GET instead of POST?
Also, if anyone has tips for working with this IBM device, they would be appreciated.
An example of the code...
var userName = txtUserName.Text.Trim();
var password = txtPassword.Text.Trim();
var authResult = GetAuthService().AuthenticateUser(userName, password);
if (authResult == true)
{
//set forms auth cookie
Response.Redirect("Menu.aspx", false);
}
else
{
lblError.Text = "Unable to login";
}
A POST followed by a redirect is a usual mechanism found in many implementation. For example, consider using JAAS authentication. You present a form to a user and it is posted on '*/j_security_check' URL. Once authenticated you are redirected to a resource page, else you are re-directed to an error page.
I am not sure what is configured on datapower, but if your developer is using MPGW construct for this, then he can try playing around with two properties found in 'Advanced' tab of it. One is 'follow redirects' and another one is allow 'empty request'.
May be this helps you.

How do I sign out a user authenticated on an external page with CAS, FormsAuthentication

I've wrapped some code around my project to enable user authentication. It seems to be using FormsAuthentication as well as .NetCasAuthentication. When a user wants to login, I redirect them to an external page whose URL is saved in
DotNetCasClient.CasAuthentication.FormsLoginUrl, and that, after a successful login attempt, sets the User.Identity object. So far so good.
Now, how do I properly sign the user out?
I've tried
FormsAuthentication.SignOut()
Expiring a couple cookies as suggested here
And even explicitly nullifying the User object: HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
But when I send another request to my application, it's still able to find that user's information somewhere.
Does CasAuthentication save to a cookie? Or is it more likely that it's in some unique location as defined by the external login page? I have the option of redirecting to the corresponding external logout page, but I don't know how to do that without redirecting to it and leaving my application, and I don't want to do that.
Thanks for reading.
I'm still not quite sure what was causing the phantom log out, but I was able to fix the issue I was having.
I included an iframe in my application's login and logout pages, whose sources (src) are pointed at the external login and logout pages, respectively. To tell CAS where to redirect to after validating FormsAuthentication credentials, I had to append at the end of the login iframe's src url a query string that looks like ?TARGET=http%3a%2f%2fsome.url.aspx
(The target url is escaped.
'%3a' is url encoding for a colon (:) and '%2f' is a forward slash (/))
So, say, the external login url was https://www.externalsite.com/login and I wanted to redirect to my welcome page http://www.mysite.com/welcome.aspx after logging in, my application's login page iframe src would need to be
`https://www.externalsite.com/login?TARGET=http%3a%2f%2fwww.mysite.com%2fwelcome.aspx`
After doing that, everything seems to be working fine.
I couldn't find documentation for the TARGET query string, but it seems to be related to the 'targetService' parameter described here.

Session lost after first Twitter OAuth request

Using ASP.NET MVC, sessions are stored in SQL database (never had a problem with them, and didn't use web farm). Using also Twitterizer2 library. Using Firefox.
First request, no browser instances is opened. Browser instance is started.
We have simple form "Publish on twitter" and submit button Share.
When Share is clicked we store message in Session and redirect to Twitter's OAuth authentication (on POST submit).
We authenticate OK and return to our Action and before posting to Twitter we check if message is stored in Session (and it isn't! - it is lost immediately after Twitter redirection)
When we try another messsage Share it is now working (Session).
We solved it using a Cookie but we don't have a clue while we lost Session (first time) after returning from Twitter.
Any deas?
I'd like to ask how did you maintained the session without cookie the first time?
I think the problem can be of the cookie set process. I also experienced similar problem before a couple of weeks.
The problem was that when I make request for REQUEST token, this request is internal HTTP request (not via user browser). As a response to this request I get REQUEST token and then set it in the user session.
$token = getRequestToken();
$_SESSION['token'] = $token;
However, if the user just came to my site for first time without a session, he does not have a session cookie to sent me. Internally at the web site I have created a session for him, and stored the token inside it, but then instead of sending him response with cookie headers included, so that he "accepts" my session, I make redirect to the provider authorize endpoint. This way, the user does not get the session cookie, and when he is returned back, he is like a new user for my site.
This is the flow of the process that happened to me:
create user session in the database
setcookie(usersession) // add headers to the eventual response
get request token
set the token in the session
redirect the user (user does not receive the session cookie)
user goes to authorization point
user returns, but he is a new user for me
I'd be interested to know if you had similar problem :)
Best regards
check the request and callback domain are the same
i.e. you are making request for oauth from localhost and callback to 127.0.0.1

Categories