Extend Waffle to Limit Which Window User can Access

We want to use windows integrated authentication to authenticate user and only allow user who started the application to access it. 

We can easily implement this by extending Waffle.
Waffle can do windows integrated authentication for us, after that we just need check whether the user name and domain of the logged-on user is same as the account who starts the application.
Implementation Code
After waffle.servlet.NegotiateSecurityFilter, the following filter would check whether user name and domain of the remote user and the user who starts the web application matches.
The complete code can be found at Github.
We can get the user who starts the web application by the following code:
NTSystem system = new NTSystem();
String runasUser = system.getName();
String runasDomain = system.getDomain();

There are several ways to get user name and domain of remote logged-on user:
1.  waffle.servlet.NegotiateSecurityFilter save waffle.servlet.WindowsPrincipal instance in session. We can get user name and domain info from WindowsPrincipal.
request.getSession().setAttribute(PRINCIPAL_SESSION_KEY,windowsPrincipal);
2.  waffle.servlet.NegotiateSecurityFilter add windowsPrincipal into subject, and save subject into session. Form subject instance, we can get needed info.
subject.getPrincipals().add(windowsPrincipal);
session.setAttribute("javax.security.auth.subject", subject);

package src.main.java.org.codeexample.jeffery.misc.waffle;

import waffle.servlet.NegotiateSecurityFilter;
import waffle.servlet.WindowsPrincipal;
import com.sun.jna.platform.win32.Secur32;
import com.sun.jna.platform.win32.Secur32Util;
import com.sun.security.auth.module.NTSystem;

public class OnlyAllowUserStartItFilter implements Filter {
  protected static final Logger logger = LoggerFactory
      .getLogger(NegotiateSecurityFilter.class);
  private static final String PRINCIPAL_SESSION_KEY = NegotiateSecurityFilter.class
      .getName() + ".PRINCIPAL";
  
  @Override
  public void doFilter(ServletRequest sreq, ServletResponse sres,
      FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) sreq;
    boolean valid = false;    
    HttpSession session = request.getSession(false);
    if (session != null) {
      WindowsPrincipal winPrincipal = (WindowsPrincipal) session
          .getAttribute(PRINCIPAL_SESSION_KEY);
      valid = validateRemoteUser(winPrincipal);
    }
    if (!valid) {
      sendUnauthorized(sres);
    } else {
      chain.doFilter(sreq, sres);
    }
  }
  private boolean validateRemoteUserViaWinPrincipal(Subject subject) {
    boolean valid = false;
    Set<Principal> principals = subject.getPrincipals();
    WindowsPrincipal winPrincipal = null;
    for (Principal principal : principals) {
      if (principal instanceof WindowsPrincipal) {
        winPrincipal = (WindowsPrincipal) principal;
      }
    }
    valid = validateRemoteUser(winPrincipal);
    return valid;
  }
  private boolean validateRemoteUser(WindowsPrincipal winPrincipal) {
    boolean valid = false;
    if (winPrincipal != null) {
      String fqn = winPrincipal.getName();
      int atIdx = fqn.indexOf('\\');
      String remoteDomain = null, remoteUser = null;
      if (atIdx > -1) {
        remoteDomain = fqn.substring(0, atIdx);
        remoteUser = fqn.substring(atIdx + 1);
      } else {
        remoteUser = fqn;
      }
      NTSystem system = new NTSystem();
      valid = validDomain(remoteDomain, system)
          && validateUser(remoteUser, system);
    }
    return valid;
  }
  private boolean validateRemoteUserViaSecur32() {
    boolean valid = false;
    String remoteUserInfo = Secur32Util
        .getUserNameEx(Secur32.EXTENDED_NAME_FORMAT.NameSamCompatible);
    if (remoteUserInfo != null) {
      String remoteDomain = null, remoteUser = null;
      if (atIdx > -1) {
        remoteDomain = remoteUserInfo.substring(0, atIdx);
        remoteUser = remoteUserInfo.substring(atIdx + 1);
      } else {
        remoteUser = remoteUserInfo;
      }
      
      NTSystem system = new NTSystem();
      valid = validDomain(remoteDomain, system)
          && validateUser(remoteUser, system);
    }
    return valid;
  }
  
  private boolean validateUser(String remoteUser, NTSystem system) {
    boolean valid = false;
    String runasUser = system.getName();
    if (runasUser != null) {
      if (runasUser.equals(remoteUser)) {
        valid = true;
      }
    } else {
      // this is unlikely to happen
      logger.error("runasUser is null, remoteUser: " + remoteUser);
      if (remoteUser == null) {
        valid = true;
      }
    }
    return valid;
  }
  private boolean validDomain(String remoteDomain, NTSystem system) {
    boolean valid = false;
    String runasDomain = system.getDomain();
    if (runasDomain != null) {
      if (runasDomain.equalsIgnoreCase(remoteDomain)) {
        valid = true;
      }
    } else {
      if (remoteDomain == null) {
        valid = true;
      }
    }
    return valid;
  }
  private void sendUnauthorized(ServletResponse sres) throws IOException {
    HttpServletResponse response = (HttpServletResponse) sres;
    response.setHeader("Connection", "close");
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
        "This application can be only accessed by user who started it.");
    response.flushBuffer();
  }
}
Define waffle.servlet.NegotiateSecurityFilter and OnlyAllowUserStartItFilter
Next, we need define these 2 filters in web.xml, we need make sure we first define waffle.servlet.NegotiateSecurityFilter, then define OnlyAllowUserStartItFilter, to make NegotiateSecurityFilter run first, then run OnlyAllowUserStartItFilter.

As we are using jetty, and all applications in the jetty need this feature, we define these 2 filters in our own webdefault.xml.
Post a Comment

Labels

Java (159) Lucene-Solr (112) Interview (61) All (58) J2SE (53) Algorithm (45) Soft Skills (38) Eclipse (33) Code Example (31) Linux (25) JavaScript (23) Spring (22) Windows (22) Web Development (20) Tools (19) Nutch2 (18) Bugs (17) Debug (16) Defects (14) Text Mining (14) J2EE (13) Network (13) Troubleshooting (13) PowerShell (11) Chrome (9) Design (9) How to (9) Learning code (9) Performance (9) Problem Solving (9) UIMA (9) html (9) Http Client (8) Maven (8) Security (8) bat (8) blogger (8) Big Data (7) Continuous Integration (7) Google (7) Guava (7) JSON (7) Shell (7) ANT (6) Coding Skills (6) Database (6) Lesson Learned (6) Programmer Skills (6) Scala (6) Tips (6) css (6) Algorithm Series (5) Cache (5) Dynamic Languages (5) IDE (5) System Design (5) adsense (5) xml (5) AIX (4) Code Quality (4) GAE (4) Git (4) Good Programming Practices (4) Jackson (4) Memory Usage (4) Miscs (4) OpenNLP (4) Project Managment (4) Spark (4) Testing (4) ads (4) regular-expression (4) Android (3) Apache Spark (3) Become a Better You (3) Concurrency (3) Eclipse RCP (3) English (3) Happy Hacking (3) IBM (3) J2SE Knowledge Series (3) JAX-RS (3) Jetty (3) Restful Web Service (3) Script (3) regex (3) seo (3) .Net (2) Android Studio (2) Apache (2) Apache Procrun (2) Architecture (2) Batch (2) Bit Operation (2) Build (2) Building Scalable Web Sites (2) C# (2) C/C++ (2) CSV (2) Career (2) Cassandra (2) Distributed (2) Fiddler (2) Firefox (2) Google Drive (2) Gson (2) How to Interview (2) Html Parser (2) Http (2) Image Tools (2) JQuery (2) Jersey (2) LDAP (2) Life (2) Logging (2) Python (2) Software Issues (2) Storage (2) Text Search (2) xml parser (2) AOP (1) Application Design (1) AspectJ (1) Chrome DevTools (1) Cloud (1) Codility (1) Data Mining (1) Data Structure (1) ExceptionUtils (1) Exif (1) Feature Request (1) FindBugs (1) Greasemonkey (1) HTML5 (1) Httpd (1) I18N (1) IBM Java Thread Dump Analyzer (1) JDK Source Code (1) JDK8 (1) JMX (1) Lazy Developer (1) Mac (1) Machine Learning (1) Mobile (1) My Plan for 2010 (1) Netbeans (1) Notes (1) Operating System (1) Perl (1) Problems (1) Product Architecture (1) Programming Life (1) Quality (1) Redhat (1) Redis (1) Review (1) RxJava (1) Solutions logs (1) Team Management (1) Thread Dump Analyzer (1) Visualization (1) boilerpipe (1) htm (1) ongoing (1) procrun (1) rss (1)

Popular Posts