I want to implement single sign on from my website(assume it as a.com) to vendor website(assume it as b.com)
My vendor is providing a service which will take user Id as input and returns token and cookies in response header. I need to call this service and redirect to vendor url with session token through post request and set cookies(which are received from service response).
In my code after making service call i am returning url and token to a jsp and cookies in httpservletresponse . Javascript in this jsp will autosubmit the form on page load to make post call. But when it is redirected, browser is not setting the b.com cookies in the request header.
Controller code :
#RequestMapping(value = "/sso", method = RequestMethod.GET)
public String ssoToVendor(final Model model, final HttpServletResponse response) {
/**
*Service call happens here and returns tok
*/
model.addAttribute("url","https:\\b.com");
model.addAttribute("tok",tok);
for (String cookie : cookies) {
response.addHeader("Set-Cookie", cookie);
}
return "dummyjsp"
}
JSP sample code :
<body>
<form id="redirect" action="${url}" name="redirect" method="POST">
<input type="hidden" name="tok" id="tok" value="${tok}"/>
</form>
</body>
<script type="text/javascript">
var redirect = document.getElementById("redirect");
redirect.submit();
</script>
I know that it is not possible to set cross domain cookies but some how there is another application which is implemented in c# is able to set those cookies.
Is there a way we can set b.com cookies in response header and that is created by browser and sent to b.com when redirected from a.com in java.
Related
I set a cookie on ajax response call like this:
return response($response, 200)->cookie('xid', $token, 2*24*60);
The above creates a cookie like this (which is the token value, raw, non-encrypted):
You can see this when running this code in the view:
<script type="text/javascript">
var tid = "{{ Cookie::get('xid') }}";
var tid = "{{ $_COOKIE['xid'] }}";
</script>
I get the following output:
If I check the "laravel_session" cookie instead, the output is correct (it's encrypted):
Any ideas why the xid cookie is not being encrypted? There are no exceptions in the middleware.
Solved by adding the EncryptCookie class in the api middlewaregroups in the Kernel as per Laravel session cookie not encrypted when using AJAX
Current status :
If any session time out occurs, redirectToLogin function in FacesAjaxAwareUserFilter will be executed. From there I can redirect to any page I need. I get the URI in all cases.
It's all working fine and big thanks to BalusC. :)
Now the second part which makes the issue
Redirect to login and come back to the previous page.
For Eg :
Page 5----> Login------> Page 5
I have appended the redirect URI to the login URI and retrieved the values from the bean.
But the problem is that I have 2 pages before the user login. A login mode selection page (ie; google authentication or default login) and the page that reads the username and password.
How can I pass the redirect URI through both the pages.?
This is the code I have used to redirect at Ajax time out and in normal session time out.
Class FacesAjaxAwareUserFilter
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
res.setContentType("text/xml");
res.setCharacterEncoding("UTF-8");
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() + getLoginUrl()+"?redirectUrlPattern="+request.getRequestURI());
}
else {
if (request.getRequestedSessionId()!=null && (!SecurityUtils.getSubject().isAuthenticated() || !request.isRequestedSessionIdValid())) {
response.sendRedirect(getLoginUrl()+"?redirectUrlPattern="+request.getRequestURI());
return;
}
super.redirectToLogin(req, res);
}
Method used is FullAjaxExceptionHandlerFactory in Omniface.
I have used a method of appending the values to the URI, but it fails to identify whether the session is expired or a session not created (when a user logs in at first).
Problem Code
if (request.getRequestedSessionId()!=null && (!SecurityUtils.getSubject().isAuthenticated() || !request.isRequestedSessionIdValid()))
I am looking for a way to identify the expired session from new session created before login.
Wish to implement this in a Better Way.
A method which will not append present URI with the redirect URL is most welcomed.
I have founded out a solution but still i don't find it as the best solution. Any other answer for doing it is greatly appreciated.
Step 1
Configure the application to detect Ajax Timeout and normal timeout. This is how i did it..!!
Step 2
Finding the URI when session timeout occurs, using this.
FacesAjaxAwareUserFilter will grab the ServletRequest and ServletResponse for you.
form that you can convert that to HttpServletRequest and HttpServletResponse using this
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) res;
The request.getRequestURI() will get you the redirect URI
String redirectURI=request.getRequestURI();
Now you want to save this to some storage so that you can use it in any place you want. The only way i found is to append it with URL using this.
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() + "/sessionexpired"+"?redirectUrlPattern="+request.getRequestURI());
or
response.sendRedirect("/sessionexpired"+"?redirectUrlPattern="+request.getRequestURI());
Now on the page load of my sessionExpiry page bean, i used this to grab the value passed through the URL
redirectUrl=FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("redirectUrlPattern");
Now using JavaScript i set that value of redirectUrl to localStorage. This is how you can save values to local storage.
This is my sessionexpiry.xhtml page.
<script type="text/javascript">
function setRedirectURIToLocalStorage(){
if(typeof(Storage)!=="undefined")
{
localStorage.redirectURI=document.getElementById("redirectUrl").value;
window.location.href="/login";
}
}
</script>
</h:head>
<h:body id="body" onload="setRedirectURIToLocalStorage()">
<f:view contentType="text/html">
<h:form prependId="false" >
<h:inputHidden id="redirectUrl" value="#{sessionExpBean.redirectUrl}" />
<h:outputText value="Session Expired... Redirecting...!!"></h:outputText>
</h:form>
</f:view>
</h:body>
The page will call setRedirectURIToLocalStorage() function onLoad
and then it set the values to the localStorage. Thus the redirect
value is available all across the browser. You can use that in any
page you need.!! All you need to do is to check in this variable
localStorage.redirectURI
I am implementing an auth system in my angular js app.
What I am planning it like below:
Get user info(name and pass from login form)
Check whether user exists or not
if exists server respond with a session cookie and frontend will redirect to a certain page.
then user will do some task which will generate API request
API request should have cookie information that was sent on step 3
server check whether the cookie was generated or not and if cookie was found then respond with the API request results. And in my service I am doing something like
MyApp.service('myAuth', function($http, $q) {
this.authHeader = null;
this.checkAuth = function(){
//do api call and if success sets this.authHeader = response
}
this.isAuthenticaed = function(){
this.authHeader ? return this.authHeder : return false;
}
After submitting the login form I will call checkAuth and get my session cookie back from my server, how I can add the cookie information while doing the next REST call and also when user will navigate throughout the application after log in I do want to check each time isAuthenticaed true or false, in Angularjs when it will navigate to another page does it resets after setting it true from the first call? And is my approach 1-6 good or do you have any specific suggestions?
Btw I checked previous so entries but those are not what I want to know.
I am not sure about your backend, but this is how I would do it
Create a separate login page (dedicated url not angular sub view or
modal dialog).
If the user is not authenticated redirect to this login
page. This is done by server redirects. This page may or may not use
angular framework, as it just involves sending a user\password to
server.
Make a POST (not AJAX request) from the login page, and verify on server.
On the server set the auth cookie. (Different frameworks do it differently. ASP.Net sets form authentication cookie.)
Once the user is authenticated redirect user to the actual angular app and load all its components.
This saves any code require to manage authentication on client side in Angular. If the user lands on this page he is authenticated and has the cookie.
Also default browser behavior is to send all cookies associated with a domain with each request, so you don't have to worry if angular is sending some cookie or not.
I use the http-auth-interceptor. http://ngmodules.org/modules/http-auth-interceptor
In my backend (asp.net mvc) I build a simple Authentication Service and return an http error 401 if the user is not authenticated.
Then I handle the error with a login-view in the SPA site.
The ideas put forth by the previous answers will work, but I think they're overkill. You don't need anything this complex.
how I can add the cookie information while doing the next REST call
Turn on withCredentials by default inside $httpProvider like so:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]);
Then remove the wildcard (if you had one) from the CORS-related headers, and set allow-credentials, on the server side. In my case, using Python + Flask + Flask-Restful, it's super easy and looks like this:
import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
api.decorators = [cors.crossdomain(origin='http://localhost:8100', credentials=True)]
Now cookies will be set and returned automatically and transparently by the browser. See these threads for more info:
$http response Set-Cookie not accessible
Angularjs $http does not seem to understand "Set-Cookie" in the response
when user will navigate throughout the application after log in I do want to check each time isAuthenticaed true or false
As suggested above, have the server return 401 if the auth session expires or is deleted, and use $httpInterceptor in Angular to catch this like so:
app.config(function($httpProvider) {
var interceptor =
function($q, $rootScope) {
return {
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status==401) {
// Modify this part to suit your needs.
// In my case I broadcast a message which is
// picked up elsewhere to show the login screen.
if (!rejection.config.url.endsWith('/login'))
{
$rootScope.$broadcast('auth:loginRequired');
}
}
return $q.reject(rejection)
}
}
};
$httpProvider.interceptors.push(interceptor);
});
(Disclosure: I'm one of the developers of UserApp)
You could use the third-party service UserApp for this, together with the AngularJS module.
Check out the getting started guide, or take the course on Codecademy. Here's some examples of how it works:
Login form with error handling:
<form ua-login ua-error="error-msg">
<input name="login" placeholder="Username"><br>
<input name="password" placeholder="Password" type="password"><br>
<button type="submit">Log in</button>
<p id="error-msg"></p>
</form>
User info is accessed using the user service: user.current.email
Or in the template: <span>{{ user.email }}</span>
Signup form with error handling:
<form ua-signup ua-error="error-msg">
<input name="first_name" placeholder="Your name"><br>
<input name="login" ua-is-email placeholder="Email"><br>
<input name="password" placeholder="Password" type="password"><br>
<button type="submit">Create account</button>
<p id="error-msg"></p>
</form>
ua-is-email means that the username is the same as the email.
How to specify which routes that should be public, and which route that is the login form:
$routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true});
$routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});
The .otherwise() route should be set to where you want your users to be redirected after login. Example:
$routeProvider.otherwise({redirectTo: '/home'});
Log out link:
<a href="#" ua-logout>Log Out</a>
Hide elements that should only be visible when logged in:
<div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>
And to authenticate to your back-end services, just use user.token() to get the session token and send it with the AJAX request. At the back-end, use the UserApp API to check if the token is valid or not.
If you need any help, just let me know :)
I am developing application using Ajax and jsp.
My index.jsp page has HTML code for Login and some Ajax code in javascript. Ajax will call my another CheckLogin.jsp page
CheckLogin.jsp page checks on server for valid username and password. It returns "success" if it's valid otherwise will return message stating "username or password is not valid."
Now, when username and passwrod is valid, instead of success, I want to redirect the page to "Home.jsp" what should I do?
I am new to jsp. I appreciate your help on this.
JSP code gets run once on the server before it goes to the client, so JSP/JSTL cannot do a redirect following the success or otherwise of an AJAX call (without a full page refresh - which obviates the use of AJAX). You should to do the redirect with Javascript:
if (success) {
var successUrl = "Home.jsp"; // might be a good idea to return this URL in the successful AJAX call
window.location.href = successUrl;
}
On successful AJAX call/validation, the browser window will reload with the new URL (effectively a redirect).
Since I don't see your code, you can integrate this somewhere inside your validation :
<%
pageContext.forward("logged.jsp");
%>
function Edit() {
var allVals = $('#NEWFORMCampaignID').val();
if (allVals > 0) {
window.location = '/SMS/PrepareSMS?id='+allVals;
}
else
alert("Invalid campaign to Edit")
}
In order to redirect using Button click and pass some parameters, you can call the Controller Path(#RequestMapping(value="/SMS/PrepareSMS")) and then handle it there..
I need to know how to start a session by Ajax in Django. I'm doing exactly as described bellow, but it is not working! The request is sent correctly, but don't start any session. If a request directly without ajax it works! What is going on?
'# urls
r'^logout/$', 'autenticacao.views.logout_view'
'# view of login
def login_view(request):
username = request.GET.get('username', '')
password = request.GET.get('password', '')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse(user.get_profile().sos_user.name)
return HttpResponse('user invalido')
'# ajax in a html page
$(function(){
$.get('http://localhost:8000/logout/?username=usuario?>&password=senha', function(data){
alert(data);
});
You're not calling the login_view. You're ajax request is going to the /logout/ url which is calling the autenticacao.views.logout_view.
Also, The ?> after username=usuario doesn't look right in the your get url.
My guess is you should be doing something like http://localhost:8000/login/?username=usuario&password=senha. (but I'd need to see your login url mapping to be sure).
Also, you should be POSTing the login information and using HTTPS for security reasons, but that's a different issue.