/*=============================================================================#
# Copyright (c) 2009-2016 Stephan Wahlbrink (WalWare.de) and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of either (per the licensee's choosing)
# - the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html, or
# - the GNU Lesser General Public License v2.1 or newer
# which accompanies this distribution, and is available at
# http://www.gnu.org/licenses/lgpl.html
#
# Contributors:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.rj.server.srvstdext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import de.walware.rj.RjException;
import de.walware.rj.server.FxCallback;
import de.walware.rj.server.srvext.ServerAuthMethod;
import de.walware.rj.server.srvext.ServerUtil;
/**
* Authentication method 'none'
* without any authentication mechanism.
*/
public class FxAuthMethod extends ServerAuthMethod {
private File file;
private FileInputStream fileInputStream;
private final byte[] pendingKey = new byte[1024];
private FileChannel fileChannel;
public FxAuthMethod() {
super("fx", false);
}
@Override
public void doInit(final String arg) throws RjException {
final String configType;
final String configValue;
{ final String[] args = ServerUtil.getArgConfigValue(arg);
configType = args[0];
configValue = args[1];
}
if (configType.equals("file")) {
if (configValue == null || configValue.length() == 0) {
throw new RjException("Missing lock file name.", null);
}
this.file = new File(configValue);
try {
if (!this.file.exists()) {
this.file.createNewFile();
}
this.fileChannel = new RandomAccessFile(this.file, "rws").getChannel();
this.fileChannel.truncate(512);
}
catch (final IOException e) {
throw new RjException("Cannot read lock file.", e);
}
}
else {
throw new RjException("Unsupported configuration type '"+configType+"'.", null);
}
}
@Override
protected Callback[] doCreateLogin() throws RjException {
getRandom().nextBytes(this.pendingKey);
try {
this.fileChannel.position(this.fileChannel.size());
}
catch (final IOException e) {
throw new RjException("Cannot read lock file.", e);
}
return new Callback[] {
new NameCallback("Username"),
new FxCallback(this.file.getPath(), this.pendingKey),
};
}
@Override
protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
final String userName = ((NameCallback) callbacks[0]).getName();
final byte[] clientKey = ((FxCallback) callbacks[1]).getContent();
if (clientKey.length < 1024) {
throw new RjException("Unsufficient client key");
}
try {
if (compare(this.pendingKey) && compare(clientKey)) {
return userName;
}
}
catch (final IOException e) {
throw new RjException("Cannot read lock file.", e);
}
throw new FailedLoginException();
}
private boolean compare(final byte[] key) throws IOException {
final byte[] check = new byte[key.length];
final int n = this.fileChannel.read(ByteBuffer.wrap(check));
if (n != key.length) {
return false;
}
return Arrays.equals(key, check);
}
}