How do I pass cookies from an HttpURLConnection to WebDriver in Java? - java

I'm testing a website that requires some basic authentication. Upon successful login a session key is sent back in cookies. I've written some code to get this cookie via the web service. It ends like this:
public List<HttpCookie> getCookies(String Domain, String user, String pass) {
// Actual services to log in here
List<HttpCookie> cookies = cookieStore.getCookies();
for (HttpCookie cookie : cookies) {
System.out.println(cookie);
}
return cookies;
}
When I debug I can see my sessionKey in there with a valid value. It's got the same domain that I passed above, and a blank path like /.
Here's how I've tried adding the cookie to my WebDriver instance:
List<HttpCookie> cookies = getCookies(DOMAIN, USERNAME, PASSWORD);
for (HttpCookie cookie : cookies) {
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
String cookieDomain = cookie.getDomain();
String cookiePath = cookie.getPath();
Date cookieExpiry = new Date();
Cookie selCookie = new Cookie(cookieName, cookieValue, cookieDomain, cookiePath, cookieExpiry);
driver.manage().addCookie(selCookie);
}
driver.get(ROOT_URL+"/some/internal/page");
When I try to add selCookie I get the following error message:
org.openqa.selenium.InvalidCookieDomainException: You may only set cookies for the current domain
I'm copying the domain directly from the cookie I received. I even tried passing it as a bare String instead of relying on the getDomain() method, but it returned the same error. Any idea what could be causing it to complain?

To add a cookie to a WebDriver instance, the domain in the cookie has to match the current domain of the WebDriver instance. I was trying to add the cookie before driver had visited anything, so driver's current domain was blank. I fixed it by just sending driver to ROOT_URL before I retrieve the session cookie and add it to driver:
//Added this:
driver.get(ROOT_URL);
List<HttpCookie> cookies = getCookies(DOMAIN, USERNAME, PASSWORD);
for (HttpCookie cookie : cookies) {
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
String cookieDomain = cookie.getDomain();
String cookiePath = cookie.getPath();
Date cookieExpiry = new Date();
Cookie selCookie = new Cookie(cookieName, cookieValue, cookieDomain, cookiePath, cookieExpiry);
driver.manage().addCookie(selCookie);
}
driver.get(ROOT_URL+"/some/internal/page");

Related

How to authenticate and redirect to external application for SSO?

I am trying to implement a simple SSO feature in my spring-based web application. Scenario:
I have a main application Application1 and a secondary Application2. Both have their own login mechanisms (using spring-security login-forms) in place.
I want to implement SSO in Application1, so that when user logs-in to Application1, he can also seamlessly access Application2 via a link without having to fill up login details for Application2.
Here's what I have tried:
I created an API in Application2 which takes email as input, validates it, creates user session, and returns a url string.
#RequestMapping(path = "/sso/login", consumes = "application/json", method = RequestMethod.POST)
public String login(#RequestBody SSOparams params, HttpServletRequest req, ModelMap model) {
// 1. validates email from params
// 2. creates Authentication object:
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(username, password);
Authentication auth = authManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
HttpSession session = req.getSession(true);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);
// 3. returns a url string:
return "/user/dashboard";
}
User logs-in to Application1.
Inside Application1's home-page, when user clicks on a Application2's link, a call is made to Application1's controller method.
Application1's controller method calls Application2's login API with an email parameter, and finally redirects to the url returned from the API.
Application1's controller method:
#RequestMapping(value = "/callapplication2", method = RequestMethod.POST)
public String callapplication2(ModelMap model,HttpSession session) {
String output = "";
String redirectionUrl = "";
try {
// 1. calling application2's login API
URL url = new URL("http://localhost:8080/application2/api/sso/login");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
String input = "{\"uniqueemail\":\"abc#gmail.com\"}";
OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
while ((output = br.readLine()) != null) {
redirectionUrl = redirectionUrl + output;
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 2. returns a url
return "redirect:http://localhost:8080/application2" + redirectionUrl ;
}
All of the above is working fine. But when I login to Application1 and click on application2's link, I expect application should redirect to
http://localhost:8080/application2/user/dashboard
without having to fill up credentials.
But instead, Application2's login page opens. I can see in the network console of Chrome that /user/dashboard is being called, but since the page is secured, I am redirected to application2's login page.
Does this mean that the authentication I created using API is not being used. What am I missing?
Best approach is to set filter in web.xml and put it in top of the list.
Whenever your application will get any request it will first go to the filter and there you will check that session is present or not if its null then simply redirect to your sso login page else respective landing page.
Now in your case,
Solution i can see
1) Put filter into app2 web.xml
2) Now when you redirect from app1 to app2 (Pass one parameter anything like username, email whatever)
3) Store it into the session.
4) Whenever any request will come to app2 you will first verify session from filter, If username found that means user not need to login again else redirect to sso login page.
Thats standars steps (I belive)
5) Having a peek into your implementation.Specifically you have to add one more step into app filter. When you are redirecting from app1 for te first time with http://localhost:8080/application2/user/dashboard ( You will pass one parameter along with this url as explained above).
This let you to check 2 condition into your filter. Either request should have valid parameter or username should be into session. If any condition stated true you can let redirect request to further else you have to redirect to login page.
Hope this will help to resolve your issue.

HtmlUnit stays logged in after removing "JSESSIONID" cookie

I'm setting up remember-me authentication for my Spring Boot application an want to write a HtmlUnit test.
The problem is that deleting the "JSESSIONID" cookie does not seem to log out the webClient.
The test using remember-me authentication works fine but the test in which there should be no authentication and thus a redirect to the login page does not work (the last assertion fails).
#Test
void NoRememberMeLogin() throws IOException {
HtmlPage loginPage = webClient.getPage(baseURL + "login");
HtmlForm loginForm = loginPage.getFormByName("loginForm");
HtmlInput username = loginForm.getInputByName("username");
HtmlInput password = loginForm.getInputByName("password");
HtmlCheckBoxInput rememberMe = loginForm.getInputByName("remember-me");
username.setValueAttribute("user");
password.setValueAttribute("password");
rememberMe.setChecked(false);
// login
HtmlElement submit = loginForm.getOneHtmlElementByAttribute("input", "type", "submit");
HtmlPage afterLogin = submit.click();
// login successful?
assertThat(afterLogin.getUrl().toString(), is(baseURL + "securedPage"));
// checkl cookies
Cookie sessionCookie = webClient.getCookieManager().getCookie("JSESSIONID");
Cookie rememberMeCookie = webClient.getCookieManager().getCookie("remember-me");
assertNotNull(sessionCookie);
assertNull(rememberMeCookie);
// delete the Session cookie
webClient.getCookieManager().removeCookie(sessionCookie);
sessionCookie = webClient.getCookieManager().getCookie("JSESSIONID");
// session cookie really is deleted
assertNull(sessionCookie);
// refresh tha page (works in browser)
afterLogin.refresh();
// check that we were redirected to login page (not working)
assertThat(afterLogin.getUrl().toString(), is(baseURL + "login"));
}
Hope you can help me, thanks!

how to get sessionId element from cookie

I am doing a webview project in android java in cordova framework .The session id is sent as cookie from the server when user logs in.I need the session id for maintaining the session. I am getting cookie as
ASP.NET_Session_Id=123345; yourAuthCookie=6415176A0448E891D99DAA57BBB7FC77785AD0A3F2BCBAF660957E1CE4A7C3D47E5FDF1DDA522FBC1306C96A50029E088805CC1ECC223CE0B4A29286327907779F5FFEBD8F6AA8B2CE685579667BB29D4CBC50C1EEA
I just want session id . How can i get just the session id from cookie?
After some research i found an answer,
public String cookieElement(String Url,String CookieName){
String CookieValue = null;
CookieManager cookieManager = CookieManager.getInstance();
String cookies = cookieManager.getCookie(Url);
String[] temp=cookies.split(";");
for (String ar1 : temp ){
if(ar1.contains(CookieName)){
String[] temp1=ar1.split("=");
CookieValue = temp1[1];
break;
}
}
return CookieValue;
}
the function can be called as
String sessionid = cookieElement("https://www.example.com/","ASP.NET_Session_Id");

Error while requesting an access token. No accessTokenResponse object recieved, maybe a non HTTP 200 received?

I was following this tutorial: https://developers.docusign.com/esign-rest-api/code-examples/config-and-auth
(I used java)
In the third step I dont know how to get the code that is sent back form DocuSign as query param in the redirect uri:
// Java request auth token
**String code = "{ENTER_AUTH_CODE_FROM_PREVIOUS_STEP}";**
// assign it to the token endpoint
apiClient.getTokenEndPoint().setCode(code);
// optionally register to get notified when a new token arrives
apiClient.registerAccessTokenListener(new AccessTokenListener() {
#Override
public void notify(BasicOAuthToken token) {
System.out.println("Got a fresh token: " + token.getAccessToken());
}
});
// following call exchanges the authorization code for an access code and updates
// the `Authorization: bearer <token>` header on the api client
apiClient.updateAccessToken();
I get an error saying the requested access token is null. Below is the error:
Error while requesting an access token. No accessTokenResponse object received, maybe a non HTTP 200 received?
Has anybody ever got the same one or could maybe someone tell me how to fix it.
I ran below code and its working fine for me, after getting code from the previous step in the URL:
public static void main(String[] args) {
String IntegratorKey = "[Your_Integrator_Key]";
String ClientSecret = "[Your_Secret_Key]";
String RedirectURI = "https://www.getpostman.com/oauth2/callback";//This REDIRECT_URI should match whats configured with IntegratorKey in your Sandbox account
String AuthServerUrl = "https://account-d.docusign.com";
String RestApiUrl = "https://demo.docusign.net/restapi";
ApiClient apiClient = new ApiClient(AuthServerUrl, "docusignAccessCode", IntegratorKey, ClientSecret);
apiClient.setBasePath(RestApiUrl);
apiClient.configureAuthorizationFlow(IntegratorKey, ClientSecret, RedirectURI);
Configuration.setDefaultApiClient(apiClient);
String code = "{ENTER_AUTH_CODE_FROM_PREVIOUS_STEP}";
apiClient.getTokenEndPoint().setCode(code);
apiClient.registerAccessTokenListener(new AccessTokenListener() {
#Override
public void notify(BasicOAuthToken token) {
System.out.println("Got a fresh token: " + token.getAccessToken());
}
});
apiClient.updateAccessToken();
}
To get the code returned by DocuSign from browser, you need to have a WEBApp to which DocuSign will redirect the browser, this same callback URL should be configured in your DS Sandbox's REDIRECT_URI, for instance if you WEBApp callback URL is http://locahost:8080/docusignapp/callback, then this should be added in REDIRECT_URI in IntegratorKey and same needs to be added when calling DS URL to authenticate a user. Once DS authenticates the user, it will redirect the browser to your APP url. On hitting your WEBApp then you need to read the URL and strip off the code part using Javascript, then run the step2 to get the access Token. A sample JS code to strip the code part is:
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
var authCode = vars["code"];
In the example which you share they did it using Standalone code, where you are manually copying the code part from the URL after authentication and running the step2.

Jersey HTTP response 200 OK but returning content wrong (checking request)

This is a follow-up question to the one I asked yesterday.
The log-in page is supposed to redirect to main page after correct username and password input, with server side returning an empty string (""). If either is incorrect, server side code returns "Username or Password are incorrect".
The page functionality worked well but when I was testing using my client side code using a correct pair of username and password, it returns "Username or Password are incorrect", with response returning 200OK.
Below is my client side code:
public static void main(String[] args){
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://localhost:8080
/qa-automation-console").path("authenticate");
Form form = new Form();
form.param("username", "username");
form.param("password", "password");
Response response = target.request().post(Entity.form(form));
//The response was 200OK.
System.out.println(response.readEntity(String.class));
}
Instead of other problems including HTML and Web.xml dependency, now I suspect the client code I wrote was not correct and when the request is sent it does not contain the correct username and password. The server side code is below:
#POST
#Produces("text/plain")
#Path("authenticate")
public String authenticate(#Context HttpServletRequest req, #QueryParam("username")
String username, #QueryParam("password") String password)
throws Exception {
Environments environments = new DefaultConfigurationBuilder().build();
final ALMProfile profile = new ALMProfile();
profile.setUrl(environments.getAutomation().getAlmProfile().getUrl());
profile.setUsername(username);
if ( !Strings.isNullOrEmpty(password) ) {
String encryptedPassword = EncryptionUtils.encrypt(password);
profile.setPassword(encryptedPassword);
}
try (ALMConnection connection = new ALMConnection(profile);) {
if (connection.getOtaConnector().connected()) {
req.getSession(true).setAttribute("username", username);
req.getSession(true).setAttribute("password", profile.getPassword());
return "";
}
} catch (Exception e) {
e.printStackTrace();
return "Username or Password are incorrect";
}
return "Username or Password are incorrect";
}
Can someone point out if the client code submits the correct request?
First of all, you probably need to check what's in your stack trace. And the value of username and password. I suspect them to be null.
Secondly, I think the problem is coming from the #QueryParam annotation.
You must use instead #FormParam
You use QueryParam when your url contain params as:
www.test.com/test?username=test
When you're sending data in a Form, you must use the annotation #FormParam

Categories