#8 Authentication implementation

This commit is contained in:
serge-rider
2020-05-01 15:55:49 +03:00
parent 04a0f12a5e
commit c2ee15380e
29 changed files with 233 additions and 76 deletions
@@ -30,6 +30,7 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.model,
io.cloudbeaver.model.resources,
io.cloudbeaver.model.session,
io.cloudbeaver.registry,
io.cloudbeaver.service,
io.cloudbeaver.service.navigator,
io.cloudbeaver.service.sql
@@ -60,6 +60,8 @@ CREATE TABLE CB_USER_CREDENTIALS(
FOREIGN KEY(USER_ID) REFERENCES CB_USER(USER_ID) ON DELETE CASCADE
);
CREATE INDEX CB_USER_CREDENTIALS_SEARCH_IDX ON CB_USER_CREDENTIALS(PROVIDER_ID,CRED_ID);
CREATE TABLE CB_USER_STATE(
USER_ID VARCHAR(32) NOT NULL,
@@ -92,16 +94,6 @@ CREATE TABLE CB_SESSION_STATE(
FOREIGN KEY(SESSION_ID) REFERENCES CB_SESSION(SESSION_ID) ON DELETE CASCADE
);
CREATE TABLE CB_SESSION_STATE(
SESSION_ID VARCHAR(64) NOT NULL,
SESSION_STATE TEXT NOT NULL,
UPDATE_TIME TIMESTAMP NOT NULL,
PRIMARY KEY(SESSION_ID),
FOREIGN KEY(SESSION_ID) REFERENCES CB_SESSION(SESSION_ID) ON DELETE CASCADE
);
CREATE TABLE CB_SESSION_LOG(
SESSION_ID VARCHAR(64) NOT NULL,
@@ -48,7 +48,7 @@
<authProvider id="local" label="Local" description="Local name/password based authentication" class="io.cloudbeaver.auth.provider.local.LocalAuthProvider">
<propertyGroup label="General">
<property id="name" label="User name" type="string" description="User name" admin="true" user="true"/>
<property id="user" label="User name" type="string" description="User name" admin="true" user="true" identifying="true"/>
<property id="password" label="User password" type="string" description="User password" admin="true" user="true"/>
</propertyGroup>
@@ -26,7 +26,6 @@ import java.util.Map;
public interface DBWAuthProvider<AUTH_SESSION> {
AUTH_SESSION openSession(
String userName,
Map<String, Object> providerConfig, // Auth provider configuration (e.g. 3rd party auth server address)
Map<String, Object> userCredentials, // Saved user credentials (e.g. associated 3rd party provider user name or realm)
Map<String, Object> authParameters // Passed auth parameters (e.g. user name or password)
@@ -18,6 +18,7 @@ package io.cloudbeaver;
import io.cloudbeaver.model.user.WebRole;
import io.cloudbeaver.model.user.WebUser;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import org.jkiss.dbeaver.model.exec.DBCException;
import java.util.Map;
@@ -33,7 +34,21 @@ public interface DBWServerController {
void setUserRoles(String userId, String[] roleIds, String grantorId) throws DBCException;
void setUserCredentials(String userId, String authProviderId, Map<String, Object> credentials) throws DBCException;
/**
* Sets user redentials for specified provider
*/
void setUserCredentials(String userId, WebAuthProviderDescriptor authProvider, Map<String, Object> credentials) throws DBCException;
/**
* Find user with matching credentials.
* It doesn't check credentials like passwords, just searches user id by identifying credentials.
*/
String findUserByCredentials(WebAuthProviderDescriptor authProvider, Map<String, Object> authParameters) throws DBCException;
/**
* Get user credentials for specified provider
*/
Map<String, Object> getUserCredentials(String userId, WebAuthProviderDescriptor authProvider) throws DBCException;
WebRole[] readAllRoles() throws DBCException;
@@ -21,6 +21,7 @@ import graphql.ErrorType;
import graphql.GraphQLError;
import graphql.language.SourceLocation;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import io.cloudbeaver.service.WebServiceBindingBase;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.utils.GeneralUtils;
@@ -98,7 +99,10 @@ public class DBWebException extends DBException implements GraphQLError {
Map<String, Object> extensions = new LinkedHashMap<>();
String stString = buf.toString();
int divPos = stString.indexOf(GraphQLEndpoint.class.getName());
int divPos = stString.indexOf(WebServiceBindingBase.class.getName());
if (divPos == -1) {
divPos = stString.indexOf(GraphQLEndpoint.class.getName());
}
if (divPos != -1) {
stString = stString.substring(0, divPos);
divPos = stString.lastIndexOf(")");
@@ -106,6 +110,12 @@ public class DBWebException extends DBException implements GraphQLError {
stString = stString.substring(0, divPos + 1);
}
}
divPos = stString.indexOf(':');
if (divPos != -1) {
String exceptionClass = stString.substring(0, divPos);
extensions.put("exceptionClass", exceptionClass);
stString = stString.substring(divPos + 1).trim();
}
extensions.put("stackTrace", stString);
int errorCode = getErrorCode();
if (errorCode != ERROR_CODE_NONE) {
@@ -17,7 +17,7 @@
package io.cloudbeaver.auth.provider.local;
import io.cloudbeaver.DBWAuthProvider;
import io.cloudbeaver.server.registry.WebAuthProviderPropertyEncryption;
import io.cloudbeaver.registry.WebAuthProviderPropertyEncryption;
import org.jkiss.dbeaver.DBException;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.SecurityUtils;
@@ -30,10 +30,12 @@ import java.util.Map;
public class LocalAuthProvider implements DBWAuthProvider<LocalAuthToken> {
public static final String PROVIDER_ID = "local";
public static final String CRED_USER = "user";
public static final String CRED_PASSWORD = "password";
@Override
public LocalAuthToken openSession(String userName, Map<String, Object> providerConfig, Map<String, Object> userCredentials, Map<String, Object> authParameters) throws DBException {
public LocalAuthToken openSession(Map<String, Object> providerConfig, Map<String, Object> userCredentials, Map<String, Object> authParameters) throws DBException {
String userName = CommonUtils.toString(authParameters.get(CRED_USER), null);
String storedPasswordHash = CommonUtils.toString(userCredentials.get(CRED_PASSWORD), null);
if (CommonUtils.isEmpty(storedPasswordHash)) {
throw new DBException("User has no password (login restricted)");
@@ -18,8 +18,8 @@ package io.cloudbeaver.model;
import io.cloudbeaver.WebAction;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.server.registry.WebServiceDescriptor;
import io.cloudbeaver.server.registry.WebServiceRegistry;
import io.cloudbeaver.registry.WebServiceDescriptor;
import io.cloudbeaver.registry.WebServiceRegistry;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.registry.language.PlatformLanguageDescriptor;
import org.jkiss.dbeaver.registry.language.PlatformLanguageRegistry;
@@ -16,7 +16,7 @@
*/
package io.cloudbeaver.model;
import io.cloudbeaver.server.registry.WebServiceDescriptor;
import io.cloudbeaver.registry.WebServiceDescriptor;
import org.jkiss.dbeaver.model.meta.Property;
/**
@@ -16,7 +16,7 @@
*/
package io.cloudbeaver.model.user;
import io.cloudbeaver.server.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import org.jkiss.dbeaver.Log;
/**
@@ -16,7 +16,7 @@
*/
package io.cloudbeaver.model.user;
import io.cloudbeaver.server.registry.WebPermissionDescriptor;
import io.cloudbeaver.registry.WebPermissionDescriptor;
import org.jkiss.dbeaver.Log;
/**
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import io.cloudbeaver.DBWAuthProvider;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -22,7 +22,6 @@ import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.impl.AbstractDescriptor;
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
@@ -74,7 +73,7 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor {
return cfg.getAttribute("icon");
}
public List<DBPPropertyDescriptor> getProperties() {
public List<WebAuthProviderPropertyDescriptor> getProperties() {
return new ArrayList<>(properties.values());
}
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import org.eclipse.core.runtime.IConfigurationElement;
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
@@ -27,6 +27,7 @@ import org.jkiss.utils.CommonUtils;
public class WebAuthProviderPropertyDescriptor extends PropertyDescriptor {
private WebAuthProviderPropertyEncryption encryption;
private boolean identifying; // Identifying parameter. Will be used during auth for user search by credentials
private boolean admin; // Parameter value can be configured in admin panel
private boolean user; // Parameter can be passed by end-user from UI
@@ -34,6 +35,7 @@ public class WebAuthProviderPropertyDescriptor extends PropertyDescriptor {
super(category, config);
this.encryption = CommonUtils.valueOf(WebAuthProviderPropertyEncryption.class, config.getAttribute("encryption"), WebAuthProviderPropertyEncryption.none);
this.identifying = CommonUtils.getBoolean(config.getAttribute("identifying"), false);
this.admin = CommonUtils.getBoolean(config.getAttribute("admin"), false);
this.user = CommonUtils.getBoolean(config.getAttribute("user"), false);
}
@@ -42,6 +44,10 @@ public class WebAuthProviderPropertyDescriptor extends PropertyDescriptor {
return encryption;
}
public boolean isIdentifying() {
return identifying;
}
public boolean isAdmin() {
return admin;
}
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import org.jkiss.utils.SecurityUtils;
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import io.cloudbeaver.WebServiceUtils;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import io.cloudbeaver.service.DBWServiceBinding;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.registry;
package io.cloudbeaver.registry;
import io.cloudbeaver.service.DBWServiceBinding;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -20,6 +20,8 @@ import io.cloudbeaver.DBWServerController;
import io.cloudbeaver.auth.provider.local.LocalAuthProvider;
import io.cloudbeaver.model.user.WebRole;
import io.cloudbeaver.model.user.WebUser;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebServiceRegistry;
import org.apache.commons.dbcp2.DriverConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
@@ -29,7 +31,6 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.runtime.LoggingProgressMonitor;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
@@ -47,7 +48,6 @@ import java.sql.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Database management
@@ -237,8 +237,13 @@ public class CBDatabase {
String clientPassword = LocalAuthProvider.makeClientPasswordHash(adminUser.getUserId(), userPassword);
Map<String, Object> credentials = new LinkedHashMap<>();
credentials.put(LocalAuthProvider.CRED_USER, adminUser.getUserId());
credentials.put(LocalAuthProvider.CRED_PASSWORD, clientPassword);
serverController.setUserCredentials(adminUser.getUserId(), LocalAuthProvider.PROVIDER_ID, credentials);
WebAuthProviderDescriptor authProvider = WebServiceRegistry.getInstance().getAuthProvider(LocalAuthProvider.PROVIDER_ID);
if (authProvider != null) {
serverController.setUserCredentials(adminUser.getUserId(), authProvider, credentials);
}
}
if (!CommonUtils.isEmpty(initialData.getRoles())) {
@@ -22,7 +22,7 @@ import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.WebDataSourceConfig;
import io.cloudbeaver.model.WebServerConfig;
import io.cloudbeaver.model.session.WebSessionManager;
import io.cloudbeaver.server.registry.WebDriverRegistry;
import io.cloudbeaver.registry.WebDriverRegistry;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Platform;
import org.jkiss.code.NotNull;
@@ -19,9 +19,10 @@ package io.cloudbeaver.server;
import io.cloudbeaver.DBWServerController;
import io.cloudbeaver.model.user.WebRole;
import io.cloudbeaver.model.user.WebUser;
import io.cloudbeaver.server.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.server.registry.WebAuthProviderPropertyDescriptor;
import io.cloudbeaver.server.registry.WebServiceRegistry;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderPropertyDescriptor;
import io.cloudbeaver.registry.WebAuthProviderPropertyEncryption;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.utils.ArrayUtils;
@@ -38,6 +39,8 @@ import java.util.stream.Collectors;
*/
class CBServerController implements DBWServerController {
private static final Log log = Log.getLog(CBServerController.class);
private final CBDatabase database;
CBServerController(CBDatabase database) {
@@ -88,18 +91,14 @@ class CBServerController implements DBWServerController {
}
@Override
public void setUserCredentials(String userId, String authProviderId, Map<String, Object> credentials) throws DBCException {
WebAuthProviderDescriptor authProvider = WebServiceRegistry.getInstance().getAuthProvider(authProviderId);
if (authProvider == null) {
throw new DBCException("Invalid auth provider '" + authProviderId + "'");
}
public void setUserCredentials(String userId, WebAuthProviderDescriptor authProvider, Map<String, Object> credentials) throws DBCException {
List<String[]> transformedCredentials;
try {
transformedCredentials = credentials.entrySet().stream().map(cred -> {
String propertyName = cred.getKey();
WebAuthProviderPropertyDescriptor property = authProvider.getProperty(propertyName);
if (property == null) {
throw new IllegalArgumentException("Invalid auth provider '" + authProviderId + "' property '" + propertyName + "'");
throw new IllegalArgumentException("Invalid auth provider '" + authProvider.getId() + "' property '" + propertyName + "'");
}
String encodedValue = CommonUtils.toString(cred.getValue());
encodedValue = property.getEncryption().encrypt(userId, encodedValue);
@@ -109,12 +108,12 @@ class CBServerController implements DBWServerController {
throw new DBCException("Error passing properties to provider", e);
}
try (Connection dbCon = database.openConnection()) {
JDBCUtils.executeStatement(dbCon, "DELETE FROM CB_USER_CREDENTIALS WHERE USER_ID=? AND PROVIDER_ID=?", userId, authProviderId);
JDBCUtils.executeStatement(dbCon, "DELETE FROM CB_USER_CREDENTIALS WHERE USER_ID=? AND PROVIDER_ID=?", userId, authProvider.getId());
if (!CommonUtils.isEmpty(credentials)) {
try (PreparedStatement dbStat = dbCon.prepareStatement("INSERT INTO CB_USER_CREDENTIALS(USER_ID,PROVIDER_ID,CRED_ID,CRED_VALUE) VALUES(?,?,?,?)")) {
for (String[] cred : transformedCredentials) {
dbStat.setString(1, userId);
dbStat.setString(2, authProviderId);
dbStat.setString(2, authProvider.getId());
dbStat.setString(3, cred[0]);
dbStat.setString(4, cred[1]);
dbStat.execute();
@@ -126,6 +125,87 @@ class CBServerController implements DBWServerController {
}
}
@Override
public String findUserByCredentials(WebAuthProviderDescriptor authProvider, Map<String, Object> authParameters) throws DBCException {
Map<String, Object> identCredentials = new LinkedHashMap<>();
for (WebAuthProviderPropertyDescriptor prop : authProvider.getProperties()) {
if (prop.isIdentifying()) {
String propId = CommonUtils.toString(prop.getId());
Object paramValue = authParameters.get(propId);
if (paramValue == null) {
throw new DBCException("Authentication parameter '" + prop.getId() + "' is missing");
}
if (prop.getEncryption() == WebAuthProviderPropertyEncryption.hash) {
throw new DBCException("Hash encryption can't be used in identifying credentials");
}
identCredentials.put(propId, paramValue);
}
}
if (identCredentials.isEmpty()) {
throw new DBCException("No identifying credentials in provider '" + authProvider.getId() + "'");
}
StringBuilder sql = new StringBuilder();
sql.append("SELECT UC.USER_ID FROM CB_USER_CREDENTIALS UC\n");
for (int joinNum = 0; joinNum < identCredentials.size() - 1; joinNum++) {
String joinAlias = "UC" + (joinNum + 2);
sql.append(",CB_USER_CREDENTIALS ").append(joinAlias).append(" ON ")
.append(joinAlias).append(".USER_ID=UC.USER_ID")
.append(joinAlias).append(".PROVIDER_ID=UC.PROVIDER_ID AND ")
.append(joinAlias).append("CRED_ID=? AND ")
.append(joinAlias).append("CRED_VALUE=?");
}
sql.append("WHERE UC.CRED_ID=? AND UC.CRED_VALUE=? AND UC.PROVIDER_ID=?");
try (Connection dbCon = database.openConnection()) {
try (PreparedStatement dbStat = dbCon.prepareStatement(sql.toString())) {
int param = 1;
for (Map.Entry<String, Object> credEntry : identCredentials.entrySet()) {
dbStat.setString(param++, credEntry.getKey());
dbStat.setString(param++, CommonUtils.toString(credEntry.getValue()));
}
dbStat.setString(param, authProvider.getId());
try (ResultSet dbResult = dbStat.executeQuery()) {
String userId = null;
while (dbResult.next()) {
String credUserId = dbResult.getString(1);
if (userId == null) {
userId = credUserId;
} else if (!userId.equals(credUserId)) {
log.error("Multiple users associated with the same credentials! " + credUserId + ", " + userId);
}
}
return userId;
}
}
} catch (SQLException e) {
throw new DBCException("Error while searching credentials", e);
}
}
@Override
public Map<String, Object> getUserCredentials(String userId, WebAuthProviderDescriptor authProvider) throws DBCException {
try (Connection dbCon = database.openConnection()) {
try (PreparedStatement dbStat = dbCon.prepareStatement(
"SELECT CRED_ID,CRED_VALUE FROM CB_USER_CREDENTIALS\n" +
"WHERE USER_ID=? AND PROVIDER_ID=?")) {
dbStat.setString(1, userId);
dbStat.setString(2, authProvider.getId());
try (ResultSet dbResult = dbStat.executeQuery()) {
Map<String, Object> credentials = new LinkedHashMap<>();
while (dbResult.next()) {
credentials.put(dbResult.getString(1), dbResult.getString(2));
}
return credentials;
}
}
} catch (SQLException e) {
throw new DBCException("Error saving role in database", e);
}
}
@Override
public WebRole[] readAllRoles() throws DBCException {
try (Connection dbCon = database.openConnection()) {
@@ -1,8 +1,6 @@
package io.cloudbeaver.server.graphql;
import graphql.GraphQLContext;
import graphql.scalars.ExtendedScalars;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.TypeRuntimeWiring;
import io.cloudbeaver.DBWebException;
@@ -11,8 +9,8 @@ import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.DBWServiceBinding;
import io.cloudbeaver.service.DBWServiceBindingGraphQL;
import io.cloudbeaver.model.session.WebSessionManager;
import io.cloudbeaver.server.registry.WebServiceDescriptor;
import io.cloudbeaver.server.registry.WebServiceRegistry;
import io.cloudbeaver.registry.WebServiceDescriptor;
import io.cloudbeaver.registry.WebServiceRegistry;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.runtime.DBWorkbench;
@@ -34,7 +34,7 @@ import graphql.schema.idl.TypeDefinitionRegistry;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.registry.WebServiceRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.service.DBWServiceBindingGraphQL;
import org.jkiss.dbeaver.Log;
import org.jkiss.utils.IOUtils;
@@ -3,7 +3,7 @@ package io.cloudbeaver.server.jetty;
import io.cloudbeaver.service.DBWServiceBindingServlet;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import io.cloudbeaver.server.registry.WebServiceRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -26,9 +26,9 @@ type AuthProviderInfo {
}
type UserAuthInfo {
userName: String!
loginTime: DateTime
userId: String!
authProvider: String!
loginTime: DateTime!
# Optional login message
message: String
@@ -27,7 +27,7 @@ import java.util.Map;
*/
public interface DBWServiceAuth extends DBWService {
String authLogin(WebSession webSession, String providerId, Map<String, Object> credentials) throws DBWebException;
WebAuthInfo authLogin(WebSession webSession, String providerId, Map<String, Object> credentials) throws DBWebException;
void authLogout(WebSession webSession) throws DBWebException;
@@ -16,6 +16,8 @@
*/
package io.cloudbeaver.service.auth;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.Date;
/**
@@ -23,23 +25,41 @@ import java.util.Date;
*/
public class WebAuthInfo {
private String userName;
private Date loginTime;
private String userId;
private String authProvider;
private Object authToken;
private OffsetDateTime loginTime;
private String message;
public String getUserName() {
return userName;
public String getUserId() {
return userId;
}
public void setUserName(String userName) {
this.userName = userName;
public void setUserId(String userId) {
this.userId = userId;
}
public Date getLoginTime() {
public String getAuthProvider() {
return authProvider;
}
public void setAuthProvider(String authProvider) {
this.authProvider = authProvider;
}
public Object getAuthToken() {
return authToken;
}
public void setAuthToken(Object authToken) {
this.authToken = authToken;
}
public OffsetDateTime getLoginTime() {
return loginTime;
}
public void setLoginTime(Date loginTime) {
public void setLoginTime(OffsetDateTime loginTime) {
this.loginTime = loginTime;
}
@@ -17,13 +17,11 @@
package io.cloudbeaver.service.auth;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.server.registry.WebServiceRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.service.auth.impl.WebServiceAuthImpl;
import java.util.Date;
/**
* Web service implementation
*/
@@ -39,15 +37,10 @@ public class WebServiceBindingAuth extends WebServiceBindingBase<DBWServiceAuth>
public void bindWiring(DBWBindingContext model) throws DBWebException {
model.getQueryType()
.dataFetcher("authLogin", env -> {
String userId = getService(env).authLogin(
return getService(env).authLogin(
getWebSession(env),
env.getArgument("providerId"),
env.getArgument("provider"),
env.getArgument("credentials"));
WebAuthInfo authInfo = new WebAuthInfo();
authInfo.setUserName(userId);
authInfo.setLoginTime(new Date());
authInfo.setMessage("User logged in");
return authInfo;
})
.dataFetcher("authLogout", env -> {
getService(env).authLogout(getWebSession(env));
@@ -16,10 +16,19 @@
*/
package io.cloudbeaver.service.auth.impl;
import io.cloudbeaver.DBWServerController;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.service.auth.DBWServiceAuth;
import io.cloudbeaver.service.auth.WebAuthInfo;
import org.jkiss.dbeaver.DBException;
import org.jkiss.utils.CommonUtils;
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.Map;
/**
@@ -27,10 +36,38 @@ import java.util.Map;
*/
public class WebServiceAuthImpl implements DBWServiceAuth {
@Override
public String authLogin(WebSession webSession, String providerId, Map<String, Object> credentials) throws DBWebException {
return null;
public WebAuthInfo authLogin(WebSession webSession, String providerId, Map<String, Object> authParameters) throws DBWebException {
if (CommonUtils.isEmpty(providerId)) {
throw new DBWebException("Missing auth provider parameter");
}
WebAuthProviderDescriptor authProvider = WebServiceRegistry.getInstance().getAuthProvider(providerId);
if (authProvider == null) {
throw new DBWebException("Invalid auth provider '" + providerId + "'");
}
DBWServerController serverController = CBPlatform.getInstance().getApplication().getServerController();
try {
String userId = serverController.findUserByCredentials(authProvider, authParameters);
if (userId == null) {
// User doesn't exist. We can create new user automatically if auth provider supports this
throw new DBWebException("Invalid user credentials");
}
Map<String, Object> userCredentials = serverController.getUserCredentials(userId, authProvider);
Object authToken = authProvider.getInstance().openSession(
Collections.emptyMap(),
userCredentials,
authParameters);
WebAuthInfo authInfo = new WebAuthInfo();
authInfo.setUserId(userId);
authInfo.setLoginTime(OffsetDateTime.now());
authInfo.setAuthProvider(authProvider.getId());
authInfo.setAuthToken(authToken);
authInfo.setMessage("Logged using " + authProvider.getLabel() + " provider");
return authInfo;
} catch (DBException e) {
throw new DBWebException("User authentication failed", e);
}
}
@Override