#8 Permission check

This commit is contained in:
serge-rider
2020-05-01 20:13:39 +03:00
parent 2bc9560ee1
commit e3830fef64
7 changed files with 110 additions and 31 deletions
@@ -57,6 +57,11 @@ public class DBWebException extends DBException implements GraphQLError {
super(makeMessage(message, cause), cause);
}
public DBWebException(String message, String errorCode, Throwable cause) {
this(message, cause);
this.webErrorCode = errorCode;
}
public DBWebException(Throwable cause, DBPDataSource dataSource) {
super(cause, dataSource);
}
@@ -0,0 +1,34 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2020 DBeaver Corp and others
*
* 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 io.cloudbeaver;
/**
* The activator class controls the plug-in life cycle
*/
public class DBWebExceptionAccessDenied extends DBWebException {
public static final String ERROR_CODE_ACCESS_DENIED = "accessDenied";
public DBWebExceptionAccessDenied(String message) {
super(message, ERROR_CODE_ACCESS_DENIED);
}
public DBWebExceptionAccessDenied(String message, Throwable cause) {
super(message, ERROR_CODE_ACCESS_DENIED, cause);
}
}
@@ -17,9 +17,16 @@
package io.cloudbeaver;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Object association annotation
*/
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WebAction {
String[] requirePermissions() default { DBWConstants.PERMISSION_PUBLIC };
@@ -66,8 +66,8 @@ public class WebSession {
private static final AtomicInteger TASK_ID = new AtomicInteger();
private String id;
private long createTime;
private final String id;
private final long createTime;
private long lastAccessTime;
private WebUser user;
@@ -122,23 +122,26 @@ public class WebSession {
}
@Property
public String getLastAccessTime() {
public synchronized String getLastAccessTime() {
return CBConstants.ISO_DATE_FORMAT.format(lastAccessTime);
}
public long getLastAccessTimeMillis() {
public synchronized long getLastAccessTimeMillis() {
return lastAccessTime;
}
public WebUser getUser() {
public synchronized WebUser getUser() {
return user;
}
public Set<String> getSessionPermissions() {
public synchronized Set<String> getSessionPermissions() throws DBCException {
if (sessionPermissions == null) {
refreshSessionAuth();
}
return sessionPermissions;
}
public void setUser(WebUser user) {
public synchronized void setUser(WebUser user) {
if (CommonUtils.equalObjects(this.user, user)) {
return;
}
@@ -17,9 +17,9 @@
package io.cloudbeaver.model.session;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.server.CBPlatform;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.runtime.DBWorkbench;
@@ -49,11 +49,6 @@ public class WebSessionManager {
public WebSessionManager() {
}
public WebSession getWebSession(@NotNull HttpServletRequest request, boolean errorOnNoFound) throws DBWebException {
HttpSession session = getOrCreateHttpSession(request);
return getWebSession(session, true, errorOnNoFound);
}
public boolean closeSession(@NotNull HttpServletRequest request) {
HttpSession session = request.getSession();
if (session != null) {
@@ -80,20 +75,12 @@ public class WebSessionManager {
return getWebSession(request, true);
}
private HttpSession getOrCreateHttpSession(@NotNull HttpServletRequest request) {
HttpSession session = request.getSession();
if (session == null) {
session = request.getSession(true);
log.debug("New session: " + session.getId());
}
return session;
public WebSession getWebSession(@NotNull HttpServletRequest request, boolean errorOnNoFound) throws DBWebException {
return getWebSession(request, true, errorOnNoFound);
}
public WebSession getWebSession(HttpServletRequest request, boolean updateInfo, boolean errorOnNoFound) throws DBWebException {
return getWebSession(getOrCreateHttpSession(request), updateInfo, errorOnNoFound);
}
public WebSession getWebSession(HttpSession httpSession, boolean updateInfo, boolean errorOnNoFound) throws DBWebException {
HttpSession httpSession = request.getSession(true);
String sessionId = httpSession.getId();
WebSession webSession;
synchronized (sessionMap) {
@@ -113,11 +100,11 @@ public class WebSessionManager {
}
}
}
return webSession;
return webSession;
}
public WebSession tryGetWebSession(HttpSession httpSession) {
String sessionId = httpSession.getId();
public WebSession findWebSession(HttpServletRequest request) {
String sessionId = request.getSession().getId();
synchronized (sessionMap) {
return sessionMap.get(sessionId);
}
@@ -21,9 +21,13 @@ import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.DBWService;
import io.cloudbeaver.DBWebExceptionAccessDenied;
import io.cloudbeaver.WebAction;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.utils.CommonUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@@ -34,6 +38,7 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Set;
/**
* Web service implementation
@@ -63,7 +68,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
* Creates proxy for permission checks and other general API calls validation/logging.
*/
protected API_TYPE getService(DataFetchingEnvironment env) {
Object proxyImpl = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{apiInterface}, new ServiceInvocationHandler(serviceImpl));
Object proxyImpl = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{apiInterface}, new ServiceInvocationHandler(serviceImpl, env));
return apiInterface.cast(proxyImpl);
}
@@ -89,7 +94,13 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
}
protected static WebSession getWebSession(DataFetchingEnvironment env) throws DBWebException {
return getBindingContext(env).getSessionManager().getWebSession(getServletRequest(env));
return getBindingContext(env).getSessionManager().getWebSession(
getServletRequest(env));
}
protected static WebSession findWebSession(DataFetchingEnvironment env) {
return getBindingContext(env).getSessionManager().findWebSession(
getServletRequest(env));
}
protected static WebConnectionInfo getWebConnection(DataFetchingEnvironment env) throws DBWebException {
@@ -98,18 +109,50 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
private class ServiceInvocationHandler implements InvocationHandler {
private final API_TYPE impl;
private final DataFetchingEnvironment env;
ServiceInvocationHandler(API_TYPE impl) {
ServiceInvocationHandler(API_TYPE impl, DataFetchingEnvironment env) {
this.impl = impl;
this.env = env;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
WebAction webAction = method.getAnnotation(WebAction.class);
if (webAction != null) {
checkPermissions(webAction);
}
return method.invoke(impl, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
private void checkPermissions(WebAction webAction) throws DBWebExceptionAccessDenied {
String[] reqPermissions = webAction.requirePermissions();
if (reqPermissions.length == 0) {
return;
}
WebSession session = findWebSession(env);
if (session == null) {
throw new DBWebExceptionAccessDenied("Anonymous access restricted");
}
Set<String> sessionPermissions;
try {
sessionPermissions = session.getSessionPermissions();
} catch (DBCException e) {
throw new DBWebExceptionAccessDenied("Can't retrieve session permissions", e);
}
if (CommonUtils.isEmpty(sessionPermissions)) {
throw new DBWebExceptionAccessDenied("Anonymous access restricted");
}
for (String rp : reqPermissions) {
if (!sessionPermissions.contains(rp)) {
throw new DBWebExceptionAccessDenied("Access denied");
}
}
}
}
}
@@ -43,7 +43,7 @@ public class WebDataTransferServlet extends HttpServlet {
dataFileId = dataFileId.substring(1);
}
WebSession webSession = CBPlatform.getInstance().getSessionManager().tryGetWebSession(request.getSession());
WebSession webSession = CBPlatform.getInstance().getSessionManager().findWebSession(request);
if (webSession == null) {
throw new DBWebException("No active session");
}