/** * This file is part of git-as-svn. It is subject to the license terms * in the LICENSE file found in the top-level directory of this distribution * and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn, * including this file, may be copied, modified, propagated, or distributed * except according to the terms contained in the LICENSE file. */ package svnserver.ext.gitlab.auth; import org.gitlab.api.GitlabAPIException; import org.gitlab.api.models.GitlabUser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tmatesoft.svn.core.SVNException; import svnserver.auth.*; import svnserver.context.SharedContext; import svnserver.ext.gitlab.config.GitLabContext; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Map; /** * GitLab user authentiation. * * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com> */ public class GitLabUserDB implements UserDB, UserLookupVisitor { @NotNull private static final Logger log = LoggerFactory.getLogger(GitLabUserDB.class); @NotNull private static final String PREFIX_USER = "user-"; @NotNull private static final String PREFIX_KEY = "key-"; @NotNull private final Collection<Authenticator> authenticators = Collections.singleton(new PlainAuthenticator(this)); @NotNull private final GitLabContext context; public GitLabUserDB(@NotNull SharedContext context) { this.context = context.sure(GitLabContext.class); } @NotNull @Override public Collection<Authenticator> authenticators() { return authenticators; } @Nullable @Override public User check(@NotNull String userName, @NotNull String password) throws SVNException, IOException { try { return createUser(context.connect(userName, password)); } catch (GitlabAPIException e) { if (e.getResponseCode() == 401) { return null; } log.warn("User password check error: " + userName, e); return null; } catch (IOException e) { log.warn("User password check error: " + userName, e); return null; } } @Nullable @Override public User lookupByUserName(@NotNull String userName) throws SVNException, IOException { try { return createUser(context.connect().getUserViaSudo(userName)); } catch (FileNotFoundException e) { return null; } catch (IOException e) { log.warn("User lookup by name error: " + userName, e); return null; } } @Nullable @Override public User lookupByExternal(@NotNull String external) throws SVNException, IOException { final Integer userId = removePrefix(external, PREFIX_USER); if (userId != null) { try { return createUser(context.connect().getUser(userId)); } catch (FileNotFoundException e) { return null; } catch (IOException e) { log.warn("User lookup by userId error: " + external, e); return null; } } final Integer keyId = removePrefix(external, PREFIX_KEY); if (keyId != null) { try { return createUser(context.connect().getSSHKey(keyId).getUser()); } catch (FileNotFoundException e) { return null; } catch (IOException e) { log.warn("User lookup by SSH key error: " + external, e); return null; } } return null; } @Override public void updateEnvironment(@NotNull Map<String, String> env, @NotNull User userInfo) { final String externalId = userInfo.getExternalId(); if (externalId != null) { env.put("GL_ID", PREFIX_USER + externalId); } } @Nullable private Integer removePrefix(@NotNull String glId, @NotNull String prefix) { if (glId.startsWith(prefix)) { int result = 0; for (int i = prefix.length(); i < glId.length(); ++i) { final char c = glId.charAt(i); if (c < '0' || c > '9') return null; result = result * 10 + (c - '0'); } return result; } return null; } private User createUser(@NotNull GitlabUser user) { return User.create(user.getUsername(), user.getName(), user.getEmail(), user.getId().toString()); } }