/** * 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.auth; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import svnserver.StringHelper; import svnserver.parser.SvnServerParser; import svnserver.parser.SvnServerWriter; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.UUID; import java.util.function.Function; /** * Performs CRAM-MD5 authentication. * * @author Marat Radchenko <marat@slonopotamus.org> */ final class CramMD5Authenticator implements Authenticator { CramMD5Authenticator(@NotNull Function<String, UserWithPassword> lookup) { this.lookup = lookup; } @NotNull private final Function<String, UserWithPassword> lookup; @NotNull @Override public String getMethodName() { return "CRAM-MD5"; } @Nullable @Override public User authenticate(@NotNull SvnServerParser parser, @NotNull SvnServerWriter writer, @NotNull String token) throws IOException { // Выполняем авторизацию. String msgId = UUID.randomUUID().toString(); writer .listBegin() .word("step") .listBegin() .string(msgId) .listEnd() .listEnd(); // Читаем логин и пароль. final String[] authData = parser.readText().split(" ", 2); final String username = authData[0]; final UserWithPassword userWithPassword = lookup.apply(username); if (userWithPassword == null) return null; final String authRequire = hmac(msgId, userWithPassword.getPassword()); if (!authData[1].equals(authRequire)) return null; return userWithPassword.getUser(); } private static String hmac(@NotNull String sessionKey, @NotNull String password) { try { final SecretKeySpec keySpec = new SecretKeySpec(password.getBytes(), "HmacMD5"); final Mac mac = Mac.getInstance("HmacMD5"); mac.init(keySpec); return StringHelper.toHex(mac.doFinal(sessionKey.getBytes(StandardCharsets.UTF_8))); } catch (GeneralSecurityException e) { throw new IllegalStateException(e); } } }