Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use angularjs routing with CAS authentication redirect, or is angular just not usable?

Tags:

angularjs

cas

My app usually uses the following for routing:

http://angularapp.com/#/page=bannanas

However, if the user is not authenticated, the user is redirected to a CAS login page, then after login, is redirected back to:

http://angularapp.com/

Notice after redirect, CAS completely strips out the anchor/route "#/" since the anchor tag is not supported. https://issues.jasig.org/browse/CAS-1338

What is the best way around this? Is there a way I can do something like this:

http://angularapp.com/?page=bannanas

That triggers the same routing of: http://angularapp.com/#/page=bannanas

Since CAS will preserve query parameters (just not anchors) on redirection? Or is there a better way to handle this?

like image 804
Rolando Avatar asked Feb 04 '15 14:02

Rolando


1 Answers

You will need to url-encode the destination URL before redirecting to your CAS service. When the call comes back from the service you'd decode it and redirect within your application.

If you are using Java or .NET or something similar you could handle all this outside of your angular app with a filter / servlet.

But here's the basic idea. From your example your angular app is at http://angularapp.com/.

  1. User requests page http://angularapp.com/#/page=bannanas which needs to redirect to the CAS server for sign-in. You should encode that URL and pass it along as a request parameter, such as http://your-cas-site/login?returnUrl=http%3A%2F%2Fangularapp.com%2F%23%2Fpage%3Dbannanas

  2. CAS handles authentication and redirects back to your application.

  3. In your app, write an $http interceptor that watches for a request parameter of returnUrl. When you find it, decode the returnUrl=http%3A%2F%2Fangularapp.com%2F%23%2Fpage%3Dbannanas and redirect to it: http://angularapp.com/#/page=bannanas

This could also be handled externally by a filter if your application server supports that. (I've done this in Java for my app, but .NET and most other servers support the same thing).

--

Adding this example code as requested. Here's my auth filter that handles redirects to a login page.

import java.io.IOException;
import java.net.URLEncoder;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginRedirect implements Filter {

  @Override
  public void destroy() {

  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {

    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;

    // See if user has an active session.
    User currentUser = UserService.getCurrentUser(httpServletRequest.getSession());
    if (currentUser == null) {
      // No active session, need to error or redirect.
      if (httpServletRequest.getRequestURI().indexOf(httpServletRequest.getContextPath() + "/api/") == 0) {
        // For API requests, return an UNATHORIZED http response.
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
      } else {
        // For all other requests, forward the user to the login page.
        StringBuilder returnTo = new StringBuilder();
        returnTo.append(httpServletRequest.getRequestURI());
        if (httpServletRequest.getQueryString() != null) {
          returnTo.append("?");
          returnTo.append(httpServletRequest.getQueryString());
        }
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/login?returnTo=" +
            URLEncoder.encode(returnTo.toString(), "UTF-8"));
      }
    } else if (currentUser.isDeleted() || currentUser.isLocked()
        || (!currentUser.isRoleAdmin() && !currentUser.isRoleStaff())) {
      httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
    } else {
      chain.doFilter(httpServletRequest, httpServletResponse);
    }
  }

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {

  }

}
like image 152
Nicholas Hirras Avatar answered Oct 01 '22 22:10

Nicholas Hirras