/*
* Copyright 2014-2015. Adaptive.me.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.adaptive.che.infrastructure.filter;
import me.adaptive.che.infrastructure.dao.AdaptiveAuthenticationDao;
import me.adaptive.core.data.api.UserTokenEntityService;
import me.adaptive.core.data.api.WorkspaceEntityService;
import me.adaptive.core.data.api.WorkspaceMemberService;
import me.adaptive.core.data.domain.UserTokenEntity;
import me.adaptive.core.data.domain.WorkspaceEntity;
import me.adaptive.core.data.domain.WorkspaceMemberEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.user.User;
import org.eclipse.che.commons.user.UserImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.net.URI;
import java.security.Principal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by panthro on 08/06/15.
*/
@Service("adaptiveEnvironmentFilter")
public class AdaptiveEnvironmentFilter implements Filter {
private static final String TOKEN_PARAM = "token";
public static final String COOKIE_NAME = TOKEN_PARAM;
public static final Pattern WORKSPACE_ID_PATTERN = Pattern.compile(".*\\/(workspace\\w{16}).*");
public static final Logger LOG = LoggerFactory.getLogger(AdaptiveEnvironmentFilter.class);
@Autowired
private UserTokenEntityService userTokenEntityService;
@Autowired
private WorkspaceMemberService workspaceMemberService;
@Autowired
private WorkspaceEntityService workspaceEntityService;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Optional<String> tokenString;
try {
tokenString = getToken(servletRequest);
if (tokenString.isPresent() && !tokenString.get().equals(AdaptiveAuthenticationDao.COOKIE_DELETE_VALUE)) {
Optional<UserTokenEntity> token = userTokenEntityService.findByToken(tokenString.get());
if (token.isPresent()) {
EnvironmentContext environmentContext = EnvironmentContext.getCurrent();
Set<String> roles = new HashSet<>(token.get().getUser().getRoles());
//TODO Left it commented out so we can have a reference of the roles
//Collections.addAll(roles, new String[]{"workspace/admin", "workspace/developer", "system/admin", "system/manager", "user"});
//TODO Check how to set the correct workspace to the context
Optional<WorkspaceEntity> workspaceEntityOptional = getWorkspaceIdFromRequest(servletRequest);
Optional<WorkspaceMemberEntity> workspaceMemberEntity = Optional.empty();
if (workspaceEntityOptional.isPresent()) {
workspaceMemberEntity = workspaceMemberService.findByUserIdAndWorkspaceId(token.get().getUser().getUserId(), workspaceEntityOptional.get().getWorkspaceId());
} else {
Set<WorkspaceMemberEntity> workspaceMemberEntities = workspaceMemberService.findByUserId(token.get().getUser().getUserId());
if (!workspaceMemberEntities.isEmpty()) {
workspaceMemberEntity = Optional.ofNullable(workspaceMemberEntities.stream().findFirst().get());
//TODO add Account roles to the context
}
}
if (workspaceMemberEntity.isPresent()) {
roles.addAll(workspaceMemberEntity.get().getRoles());
addWorkspaceToEnvironment(workspaceMemberEntity.get().getWorkspace(), environmentContext);
}
User user = new UserImpl(token.get().getUser().getAliases().stream().filter(s -> !s.contains("@")).findFirst().get(), token.get().getUser().getUserId(), token.get().getToken(), roles, false);
environmentContext.setUser(user);
servletRequest = this.addUserInRequest((HttpServletRequest) servletRequest, user);
}
}
} finally {
filterChain.doFilter(servletRequest, servletResponse);
EnvironmentContext.reset();
}
}
/**
* //TODO this is a quick and dirty fix to work around this issue https://github.com/codenvy/everrest/issues/7
*
* @param servletRequest
* @return
*/
private boolean isBuggyRequest(ServletRequest servletRequest) {
if (servletRequest instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
return "POST".equals(request.getMethod()) && request.getContentType() != null && request.getContentType().contains(MediaType.APPLICATION_FORM_URLENCODED);
}
return false;
}
private Optional<String> getToken(ServletRequest request) {
/**
* Tries to get the token from several places in the following order
* Request Param
* Session Attribute
* Cookie
*/
/**
* Request Param
*/
Optional<String> token = !isBuggyRequest(request) ? Optional.ofNullable(request.getParameter(TOKEN_PARAM)) : getTokenFromUrl(getFullURL((HttpServletRequest) request));
if (!token.isPresent()) {
/**
* Session
*/
Object sessionToken = ((HttpServletRequest) request).getSession().getAttribute(TOKEN_PARAM);
if (sessionToken != null) {
token = Optional.of(sessionToken.toString());
}
if (!token.isPresent()) {
/**
* Cookie
*/
if (((HttpServletRequest) request).getCookies() != null) {
Optional<Cookie> cookie = Arrays.asList(((HttpServletRequest) request).getCookies())
.stream()
.filter(c -> c.getName() != null && COOKIE_NAME.equals(c.getName()))
.findFirst();
if (cookie.isPresent()) {
token = Optional.of(cookie.get().getValue());
}
}
}
}
/**
* Save the token to the session
*/
if (token.isPresent() && ((HttpServletRequest) request).getSession().getAttribute(TOKEN_PARAM) == null) {
((HttpServletRequest) request).getSession().setAttribute(TOKEN_PARAM, token.get());
}
return token;
}
protected Optional<WorkspaceEntity> getWorkspaceIdFromRequest(ServletRequest request) {
if (request instanceof HttpServletRequest) {
String requestUri = ((HttpServletRequest) request).getRequestURI();
Matcher matcher = WORKSPACE_ID_PATTERN.matcher(requestUri);
if (matcher.find()) {
return workspaceEntityService.findByWorkspaceId(matcher.group(1));
}
}
return Optional.empty();
}
protected void addWorkspaceToEnvironment(WorkspaceEntity workspaceEntity, EnvironmentContext environmentContext) {
environmentContext.setWorkspaceName(workspaceEntity.getName());
environmentContext.setWorkspaceId(workspaceEntity.getWorkspaceId());
}
@Override
public void destroy() {
}
private HttpServletRequest addUserInRequest(final HttpServletRequest httpRequest, final User user) {
return new HttpServletRequestWrapper(httpRequest) {
public String getRemoteUser() {
return user.getName();
}
public boolean isUserInRole(String role) {
return user.isMemberOf(role);
}
public Principal getUserPrincipal() {
return user::getName;
}
};
}
private Optional<String> getTokenFromUrl(String url) {
List<NameValuePair> valuePairList = URLEncodedUtils.parse(URI.create(url), "UTF-8");
Optional<NameValuePair> token = valuePairList.stream().filter(nameValuePair -> TOKEN_PARAM.equals(nameValuePair.getName())).findFirst();
if (token.isPresent()) {
return Optional.of(token.get().getValue());
}
return Optional.empty();
}
public static String getFullURL(HttpServletRequest request) {
StringBuffer requestURL = request.getRequestURL();
String queryString = request.getQueryString();
if (queryString == null) {
return requestURL.toString();
} else {
return requestURL.append('?').append(queryString).toString();
}
}
}