blob: 322abd0133910249a79eb5c432872e050dc12614 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.server.srvext.auth;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import org.eclipse.statet.rj.RjException;
import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
import org.eclipse.statet.rj.server.util.ServerUtils;
import org.eclipse.statet.rj.server.util.ServerUtils.ArgKeyValue;
/**
* Authentication method 'name-pass'
* to authenticate against a given name password pair.
*/
public class SimpleNamePassAuthMethod extends ServerAuthMethod {
private Properties users;
private byte[] digestSash;
private MessageDigest digestService;
private Charset digestCharset;
public SimpleNamePassAuthMethod() {
super("name-pass", true);
}
@Override
public void doInit(final String arg) throws RjException {
final ArgKeyValue config= ServerUtils.getArgConfigValue(arg);
try {
this.digestSash= new byte[8];
final SecureRandom random= SecureRandom.getInstance("SHA1PRNG");
random.nextBytes(this.digestSash);
this.digestService= MessageDigest.getInstance("SHA-512");
this.digestCharset= Charset.forName("UTF-8");
}
catch (final Exception e) {
throw new RjException("", e);
}
if (config.getKey().equals("file")) {
final String fileName= config.getValue();
if (fileName == null || fileName.length() == 0) {
throw new RjException("Missing password file name.", null);
}
final File file= new File(fileName);
this.users= new Properties();
try {
this.users.load(new FileInputStream(file));
}
catch (final IOException e) {
throw new RjException("Reading password file failed.", null);
}
}
else {
throw new RjException(String.format("Unsupported configuration type '%1$s'.", config.getKey()));
}
this.digestService.update(this.digestSash);
final Set<Entry<Object,Object>> entrySet= this.users.entrySet();
for (final Entry<Object, Object> entry : entrySet) {
final byte[] password= this.digestService.digest(this.digestCharset.encode(
(String) entry.getValue()).array());
entry.setValue(password);
}
System.gc();
}
@Override
protected Callback[] doCreateLogin() throws RjException {
return new Callback[] {
new NameCallback("Loginname"),
new PasswordCallback("Password", false),
};
}
@Override
protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
final String loginName= ((NameCallback) callbacks[0]).getName();
final Object object= this.users.get(loginName);
if (object instanceof byte[]) {
final byte[] loginPassword= getPass((PasswordCallback) callbacks[1]);
if (Arrays.equals((byte[]) object, loginPassword)) {
return loginName;
}
}
throw new FailedLoginException("Invalid loginname or password");
}
private byte[] getPass(final PasswordCallback callback) {
final char[] loginPassword= callback.getPassword();
final byte[] loginBytes;
if (loginPassword == null) {
return new byte[0];
}
this.digestService.update(this.digestSash);
loginBytes= this.digestService.digest(this.digestCharset.encode(
CharBuffer.wrap(loginPassword)).array());
callback.clearPassword();
Arrays.fill(loginPassword, (char) 0);
return loginBytes;
}
}