package org.openbaton.nfvo.api.interceptors;

import org.openbaton.catalogue.security.Role;
import org.openbaton.catalogue.security.Role.RoleEnum;
import org.openbaton.catalogue.security.User;
import org.openbaton.exceptions.NotFoundException;
import org.openbaton.nfvo.security.interfaces.ProjectManagement;
import org.openbaton.nfvo.security.interfaces.UserManagement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.UnauthorizedUserException;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by lto on 25/05/16.
 */
@Service
public class AuthorizeInterceptor extends HandlerInterceptorAdapter {

  private Logger log = LoggerFactory.getLogger(this.getClass());

  @Autowired private UserManagement userManagement;
  @Autowired private ProjectManagement projectManagement;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

    String projectId = request.getHeader("project-id");
    log.trace("ProjectId: " + projectId);

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    log.trace("Authentication " + authentication);
    if (authentication != null) {
      if (!(authentication instanceof AnonymousAuthenticationToken)) {
        String currentUserName = authentication.getName();
        log.trace("Current User: " + currentUserName);

        if (currentUserName.equals("anonymousUser")) {
          if (request.getMethod().equalsIgnoreCase("get")) {
            return true;
          } else {
            log.warn("AnonymousUser requesting a method: " + request.getMethod());
            return true;
          }
        } else {
          return checkAuthorization(projectId, request, currentUserName);
        }
      } else /*if (request.getMethod().equalsIgnoreCase("get"))*/ {
        log.trace("AnonymousUser requesting a method: " + request.getMethod());
        return true;
      }
    } else {
      log.warn("AnonymousUser requesting a method: " + request.getMethod());
      return true;
    }
  }

  private boolean checkAuthorization(
      String project, HttpServletRequest request, String currentUserName) throws NotFoundException {

    log.trace("Current User: " + currentUserName);
    log.trace("projectId: " + project);
    log.trace(request.getMethod() + " URI: " + request.getRequestURI());

    if ((request.getRequestURI().equals("/api/v1/projects/")
            || (request.getRequestURI().equals("/api/v1/projects"))
            || (request.getRequestURI().contains("/api/v1/users/")
                || (request.getRequestURI().contains("/api/v1/users"))))
        && request.getMethod().equalsIgnoreCase("get")) {
      return true;
    }
    if ((request.getRequestURI().contains("/api/v1/users/")
            || (request.getRequestURI().contains("/api/v1/users")))
        && request.getMethod().equalsIgnoreCase("put")) {
      return true;
    }
    log.trace(request.getMethod() + " URL: " + request.getRequestURL());
    log.trace("UserManagement: " + userManagement);
    User user = userManagement.queryDB(currentUserName);

    if (project != null) {
      if (!projectManagement.exist(project)) {
        throw new NotFoundException("Project with id " + project + " was not found");
      }
      if (user.getRoles().iterator().next().getRole().ordinal() == RoleEnum.OB_ADMIN.ordinal()) {
        log.trace("Return true for admin");
        return true;
      }

      if (user.getRoles().iterator().next().getRole().ordinal() == RoleEnum.GUEST.ordinal()) {
        if (request.getMethod().equalsIgnoreCase("get")) {
          log.trace("Return true for guest");
          return true;
        } else {
          log.trace("Return false for guest");
          return false;
        }
      }

      for (Role role : user.getRoles()) {
        String pjName = projectManagement.query(project).getName();
        log.trace(role.getProject() + " == " + pjName);
        if (role.getProject().equals(pjName)) {
          log.trace("Return true");
          return true;
        }
      }

      throw new UnauthorizedUserException(
          currentUserName + " user is not unauthorized for executing this request!");
    }
    log.trace("Return false for project null");
    return false;
  }
}

@@ -3226,24 +3226,306 @@
 true;%0A    %7D%0A
+%0A    log.trace(request.getMethod() + %22 URL: %22 + request.getRequestURL());%0A    log.trace(%22UserManagement: %22 + userManagement);%0A    User user = userManagement.queryDB(currentUserName);%0A%0A    if (user.getRoles().iterator().next().getRole().ordinal() == RoleEnum.OB_ADMIN.ordinal()) %7B%0A  
     if ((req
@@ -3564,32 +3564,34 @@
 api/v1/users/%22)%0A
+  
             %7C%7C (
@@ -3642,32 +3642,34 @@
 ers%22)))%0A        
+  
 && request.getMe
@@ -3700,32 +3700,34 @@
 %22put%22)) %7B%0A      
+  
 return true;%0A   
@@ -3715,32 +3715,34 @@
    return true;%0A
+  
     %7D%0A    log.tr
@@ -3731,33 +3731,30 @@
       %7D%0A    
-log.trace
+  if (
 (request.get
@@ -3753,38 +3753,74 @@
 uest.get
-Method() + %22 URL: %22 + 
+RequestURI().contains(%22/api/v1/users/%22)%0A              %7C%7C (
 request.
@@ -3835,122 +3835,368 @@
 stUR
-L());%0A    log.trace(%22UserManagement: %22 + userManagement);%0A    User user = userManagement.queryDB(currentUserName);
+I().contains(%22/api/v1/users%22)))%0A          && request.getMethod().equalsIgnoreCase(%22delete%22)) %7B%0A        return true;%0A      %7D%0A%0A      if ((request.getRequestURI().contains(%22/api/v1/projects/%22)%0A              %7C%7C (request.getRequestURI().contains(%22/api/v1/projects%22)))%0A          && request.getMethod().equalsIgnoreCase(%22delete%22)) %7B%0A        return true;%0A      %7D%0A    %7D
 %0A%0A  

allow delete on users and projects