RMI Anwendung mit Zugriffsschutz versehen

Status
Nicht offen für weitere Antworten.

itstata

Aktives Mitglied
Hallo,
ich stehe momentan vor folgendem Problem.
Ich möchte, dass mein RMI-Server nur Clients den Zugriff gewährt, die auch eine berächtigung haben (vereinfacht erstmal mit passwort). In meinem Buch über Rmi konnte ich nicht sehen, dass es dafür schon was gibt.
Hat jemand von euch schon dieses Problem gelöst? Ist ja eigentlich was grundlegendes. Ich hatte daran gedacht, dass er die Client-Verbindung zurückweist, allerdings weiss ich nicht, wie man das realisieren kann. Wo wäre ein eleganter weg?
 

itstata

Aktives Mitglied
ich hab mir jetzt mal einige beispiele angeschaut und auch erfolgreich getestet. das grundlegende konzept hab ich wohl erstmal nachvollzogen, allerdings will mir nicht so recht in den kopf, wie ich nun eigentlich meine klasse schütze, bzw. wo :shock:

ich muss ja irgendwo festlegen, was geschützt werden soll.
  • der client muss sich ja zwingend am server mit dem .login anmelden...
  • nur wenn dies erfolgreich ist kommt keine login-exception und mann kann methoden auf dem server nutzen


ich nutze folgende klassen:

SampleAcn
Code:
package sample;

import java.io.*;
import java.util.*;
import javax.security.auth.login.*;
import javax.security.auth.callback.*;

public class SampleAcn {

	public static void main(String[] args) {
		System.setProperty("java.security.auth.login.config",
				"D:\\Programmierung\\localTests\\bin\\samplejaas.conf");

		LoginContext lc = null;
		try {
			lc = new LoginContext("Sample", new MyCallbackHandler());
		} catch (LoginException le) {
			System.err
					.println("Cannot create LoginContext. " + le.getMessage());
			System.exit(-1);
		} catch (SecurityException se) {
			System.err
					.println("Cannot create LoginContext. " + se.getMessage());
			System.exit(-1);
		}
		// the user has 3 attempts to authenticate successfully
		int i;
		for (i = 0; i < 3; i++) {
			try {
				// attempt authentication
				lc.login();
				// if we return with no exception, authentication succeeded
				break;

			} catch (LoginException le) {

				System.err.println("Authentication failed:");
				System.err.println("  " + le.getMessage());
				try {
					Thread.currentThread().sleep(3000);
				} catch (Exception e) {
					// ignore
				}
			}
		}
		// did they fail three times?
		if (i == 3) {
			System.out.println("Sorry");
			System.exit(-1);
		}
		System.out.println("Authentication succeeded!");
	}
}

class MyCallbackHandler implements CallbackHandler {

	public void handle(Callback[] callbacks) throws IOException,
			UnsupportedCallbackException {

		for (int i = 0; i < callbacks.length; i++) {
			if (callbacks[i] instanceof TextOutputCallback) {

				// display the message according to the specified type
				TextOutputCallback toc = (TextOutputCallback) callbacks[i];
				switch (toc.getMessageType()) {
				case TextOutputCallback.INFORMATION:
					System.out.println(toc.getMessage());
					break;
				case TextOutputCallback.ERROR:
					System.out.println("ERROR: " + toc.getMessage());
					break;
				case TextOutputCallback.WARNING:
					System.out.println("WARNING: " + toc.getMessage());
					break;
				default:
					throw new IOException("Unsupported message type: "
							+ toc.getMessageType());
				}

			} else if (callbacks[i] instanceof NameCallback) {

				// prompt the user for a username
				NameCallback nc = (NameCallback) callbacks[i];

				System.err.print(nc.getPrompt());
				System.err.flush();
				nc
						.setName((new BufferedReader(new InputStreamReader(
								System.in))).readLine());

			} else if (callbacks[i] instanceof PasswordCallback) {

				// prompt the user for sensitive information
				PasswordCallback pc = (PasswordCallback) callbacks[i];
				System.err.print(pc.getPrompt());
				System.err.flush();
				pc.setPassword(readPassword(System.in));

			} else {
				throw new UnsupportedCallbackException(callbacks[i],
						"Unrecognized Callback");
			}
		}
	}

	// Reads user password from given input stream.
	private char[] readPassword(InputStream in) throws IOException {

		char[] lineBuffer;
		char[] buf;
		int i;

		buf = lineBuffer = new char[128];

		int room = buf.length;
		int offset = 0;
		int c;

		loop: while (true) {
			switch (c = in.read()) {
			case -1:
			case '\n':
				break loop;

			case '\r':
				int c2 = in.read();
				if ((c2 != '\n') && (c2 != -1)) {
					if (!(in instanceof PushbackInputStream)) {
						in = new PushbackInputStream(in);
					}
					((PushbackInputStream) in).unread(c2);
				} else
					break loop;

			default:
				if (--room < 0) {
					buf = new char[offset + 128];
					room = buf.length - offset - 1;
					System.arraycopy(lineBuffer, 0, buf, 0, offset);
					Arrays.fill(lineBuffer, ' ');
					lineBuffer = buf;
				}
				buf[offset++] = (char) c;
				break;
			}
		}

		if (offset == 0) {
			return null;
		}

		char[] ret = new char[offset];
		System.arraycopy(buf, 0, ret, 0, offset);
		Arrays.fill(buf, ' ');

		return ret;
	}
}

SampleLoginModule
Code:
package sample.module;

import java.util.*;
import java.io.IOException;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;
import sample.principal.SamplePrincipal;

public class SampleLoginModule implements LoginModule {

    // initial state
    private Subject subject;
    private CallbackHandler callbackHandler;
    private Map sharedState;
    private Map options;

    // configurable option
    private boolean debug = false;

    // the authentication status
    private boolean succeeded = false;
    private boolean commitSucceeded = false;

    // username and password
    private String username;
    private char[] password;

    // testUser's SamplePrincipal
    private SamplePrincipal userPrincipal;

    public void initialize(Subject subject, 
	           CallbackHandler callbackHandler,
			 Map<java.lang.String, ?> sharedState, 
			 Map<java.lang.String, ?> options) {
 
	this.subject = subject;
	this.callbackHandler = callbackHandler;
	this.sharedState = sharedState;
	this.options = options;

	// initialize any configured options
	debug = "true".equalsIgnoreCase((String)options.get("debug"));
    }
    public boolean login() throws LoginException {

	// prompt for a user name and password
	if (callbackHandler == null)
	    throw new LoginException("Error: no CallbackHandler available " +
			"to garner authentication information from the user");

	Callback[] callbacks = new Callback[2];
	callbacks[0] = new NameCallback("user name: ");
	callbacks[1] = new PasswordCallback("password: ", false);
 
	try {
	    callbackHandler.handle(callbacks);
	    username = ((NameCallback)callbacks[0]).getName();
	    char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
	    if (tmpPassword == null) {
		// treat a NULL password as an empty password
		tmpPassword = new char[0];
	    }
	    password = new char[tmpPassword.length];
	    System.arraycopy(tmpPassword, 0,
			password, 0, tmpPassword.length);
	    ((PasswordCallback)callbacks[1]).clearPassword();
 
	} catch (java.io.IOException ioe) {
	    throw new LoginException(ioe.toString());
	} catch (UnsupportedCallbackException uce) {
	    throw new LoginException("Error: " + uce.getCallback().toString() +
		" not available to garner authentication information " +
		"from the user");
	}

	// print debugging information
	if (debug) {
	    System.out.println("\t\t[SampleLoginModule] " +
				"user entered user name: " +
				username);
	    System.out.print("\t\t[SampleLoginModule] " +
				"user entered password: ");
	    for (int i = 0; i < password.length; i++)
		System.out.print(password[i]);
	    System.out.println();
	}

	// verify the username/password
	boolean usernameCorrect = false;
	boolean passwordCorrect = false;
	if (username.equals("testUser"))
	    usernameCorrect = true;
	if (usernameCorrect &&
	    password.length == 12 &&
	    password[0] == 't' &&
	    password[1] == 'e' &&
	    password[2] == 's' &&
	    password[3] == 't' &&
	    password[4] == 'P' &&
	    password[5] == 'a' &&
	    password[6] == 's' &&
	    password[7] == 's' &&
	    password[8] == 'w' &&
	    password[9] == 'o' &&
	    password[10] == 'r' &&
	    password[11] == 'd') {

	    // authentication succeeded!!!
	    passwordCorrect = true;
	    if (debug)
		System.out.println("\t\t[SampleLoginModule] " +
				"authentication succeeded");
	    succeeded = true;
	    return true;
	} else {

	    // authentication failed -- clean out state
	    if (debug)
		System.out.println("\t\t[SampleLoginModule] " +
				"authentication failed");
	    succeeded = false;
	    username = null;
	    for (int i = 0; i < password.length; i++)
		password[i] = ' ';
	    password = null;
	    if (!usernameCorrect) {
		throw new FailedLoginException("User Name Incorrect");
	    } else {
		throw new FailedLoginException("Password Incorrect");
	    }
	}
    }

    public boolean commit() throws LoginException {
	if (succeeded == false) {
	    return false;
	} else {
	    // add a Principal (authenticated identity)
	    // to the Subject

	    // assume the user we authenticated is the SamplePrincipal
	    userPrincipal = new SamplePrincipal(username);
	    if (!subject.getPrincipals().contains(userPrincipal))
		subject.getPrincipals().add(userPrincipal);

	    if (debug) {
		System.out.println("\t\t[SampleLoginModule] " +
				"added SamplePrincipal to Subject");
	    }

	    // in any case, clean out state
	    username = null;
	    for (int i = 0; i < password.length; i++)
		password[i] = ' ';
	    password = null;

	    commitSucceeded = true;
	    return true;
	}
    }

    public boolean abort() throws LoginException {
	if (succeeded == false) {
	    return false;
	} else if (succeeded == true && commitSucceeded == false) {
	    // login succeeded but overall authentication failed
	    succeeded = false;
	    username = null;
	    if (password != null) {
		for (int i = 0; i < password.length; i++)
		    password[i] = ' ';
		password = null;
	    }
	    userPrincipal = null;
	} else {
	    // overall authentication succeeded and commit succeeded,
	    // but someone else's commit failed
	    logout();
	}
	return true;
    }

    public boolean logout() throws LoginException {

	subject.getPrincipals().remove(userPrincipal);
	succeeded = false;
	succeeded = commitSucceeded;
	username = null;
	if (password != null) {
	    for (int i = 0; i < password.length; i++)
		password[i] = ' ';
	    password = null;
	}
	userPrincipal = null;
	return true;
    }
}

SamplePrincipal
Code:
package sample.principal;

import java.security.Principal;

public class SamplePrincipal implements Principal, java.io.Serializable {

    /**
     * @serial
     */
    private String name;

    public SamplePrincipal(String name) {
	if (name == null)
	    throw new NullPointerException("illegal null input");

	this.name = name;
    }

    public String getName() {
	return name;
    }

    public String toString() {
	return("SamplePrincipal:  " + name);
    }
    
    public boolean equals(Object o) {
	if (o == null)
	    return false;

        if (this == o)
            return true;
 
        if (!(o instanceof SamplePrincipal))
            return false;
        SamplePrincipal that = (SamplePrincipal)o;

	if (this.getName().equals(that.getName()))
	    return true;
	return false;
    }
 
    public int hashCode() {
	return name.hashCode();
    }
}

Code:
meine conf datei sieht so aus und funktioniert auch:
Sample {
   sample.module.SampleLoginModule required debug=true;
};
[/list]
 
T

tuxedo

Gast
Ich mach das meist so:

Ich hab ein Serverobject das als einzigste Methode eine login() Methode anbietet. Der Methode wird benutzername und Passwort etc. übergeben. Als Ergebnis bekommt der Client entweder NULL oder eine Exception wenn der Login falsch war, ODER er bekommt ein weiteres Serverobject das sich nur über diese Loginmethode bekommen lässt. Und in diesem Objekt sind dann die ganzen Methoden die ein authentifizierter und autorisierter Client benutzen darf.

Denke das ist einer der einfachsten und unkompliziertesten Wege.

- Alex
 

itstata

Aktives Mitglied
Aber wozu soll denn JAAS überhaupt gut sein, wenn man den server dazu auch noch neustarten muss, wenn es änderungen an der policy-datei gibt. das kommt mir alles sehr eigenartig vor. hat denn jemand schon mal JAAS implementiert und gute erfahrungen gemacht?

danke alex, ich werd das dann auch so versuchen - habs mir wohl komplizierter gemacht als es ist.
 

HoaX

Top Contributor
man muss bei jaas ja kein properties nehmen, man kann auch gegen eine datenbank authentifizieren
 
T

tuxedo

Gast
Je nachdem was man machen will und vor hat, ist JAAS etwas "überdimensioniert". Denke für einfache Sachen ist der Session-Ansatz mit einem extre Remote-Objekt einfacher zu handhaben.

- Alex
 

itstata

Aktives Mitglied
also ich hab das jetzt per rückgabe eines objekts implementiert, guter tipp von euch. damit ist das thema zumindest für mich gelöst, falls jemand mal das gleiche problem bekommt, hier der code:

auf dem Server:
Code:
...
Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
// LoginModul
RemoteLogin remote = new RemoteLoginImpl();
registry.bind("Abruf", remote);

RemoteLoginImpl (liegt nur auf Server)
Code:
public class RemoteLoginImpl extends UnicastRemoteObject implements RemoteLogin {

	private static final long serialVersionUID = 33009593583244040L;

	public RemoteLoginImpl() throws Exception {
		super(Registry.REGISTRY_PORT, new RMISSLClientSocketFactory(), new RMISSLServerSocketFactory());
	}

	public Abruf login(String in_username, String in_password) throws Exception {
		String username = "myusername";
		String password = "mypassword";

		if (username.equals(in_username) && password.equals(in_password))
			return (new AbrufImpl());
		else
			throw new RemoteLoginException("username or password incorrect");
	}
}

RemoteLogin

Abruf sind bei mir die geschützten Methoden
Code:
public interface RemoteLogin extends Remote {

	Abruf login(String username, String password) throws RemoteException, RemoteLoginException, Exception;
}

Client
Code:
Registry registry = LocateRegistry.getRegistry(host, Registry.REGISTRY_PORT);

		RemoteLogin login = (RemoteLogin) registry.lookup("Abruf");
//falls das Passwort falsch ist, kommt man also nicht an die internen methoden ran
		Abruf fd = login.login(username, password);
		String message = fd.halloweltodersowas();
[/code]
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
A Socket-Anwendung (BufferedWriter/Reader liest nicht aktuellen Wert) Netzwerkprogrammierung 6
R Anfängerbeispiel: Suche Java-Anwendung die http-Anfragen in Tomcat liest Netzwerkprogrammierung 8
L Webbasierte Anwendung - Authentifizierung über LDAP/ActiveDirectory Netzwerkprogrammierung 5
B Webview für Anwendung Netzwerkprogrammierung 7
agent47 HTTP Grundstzfrage verteilte Anwendung Netzwerkprogrammierung 20
C Mini Client-Server-Anwendung funktioniert nicht Netzwerkprogrammierung 8
S HTTP Würdet Ihr Euch bei einer intern genutzten Anwendung auf Cookies verlassen? Netzwerkprogrammierung 2
gamebreiti Socket Server / Client Anwendung Manipulation von Objekten durch Server Netzwerkprogrammierung 9
F Server Client Anwendung mit UDP Netzwerkprogrammierung 2
P Kritische Java-Anwendung und Citrix veröffentlichen Netzwerkprogrammierung 1
V erste Client - Server Anwendung, paar Fragen wie Socketverbindung checken usw. Netzwerkprogrammierung 4
S Client Anwendung mit zentraler SQL-Datenbank Netzwerkprogrammierung 3
C GWTEventService kleine Anwendung Netzwerkprogrammierung 1
T Peer-to-Peer Anwendung Netzwerkprogrammierung 2
D RMI Problem beim shutdown von verteilter CORBA-Anwendung Netzwerkprogrammierung 6
P Java Web = Webside Anwendung Netzwerkprogrammierung 2
Ollek Socket Sucher passende Server/Client Lösung für meine Anwendung Netzwerkprogrammierung 2
S Socket Einfache Client/Server-Anwendung Netzwerkprogrammierung 11
Y einfache TCP/IP Anwendung Netzwerkprogrammierung 4
J Nachricht kommt erst nach beendigung der Anwendung an Netzwerkprogrammierung 4
K Mobile online Anwendung - Java mit SAP Netzwerkprogrammierung 2
W Server-Client Anwendung Netzwerkprogrammierung 2
E Erste Server-Client Anwendung Netzwerkprogrammierung 2
J Anwendung friert bei .listNames() ein! Netzwerkprogrammierung 11
P Proxy für Anwendung setzten Netzwerkprogrammierung 3
B Server / Client Anwendung, Client GUI Probleme Netzwerkprogrammierung 11
J Mit Java Anwendung ein (externes) Programm auf einem AIX Rechner starten Netzwerkprogrammierung 6
P Mp3s Streamen - Client-Server-Anwendung Netzwerkprogrammierung 17
D Javascript Funktion aus Java Anwendung ausführen Netzwerkprogrammierung 5
M Verteilte Anwendung - welche Technik? Netzwerkprogrammierung 31
A Verständnisproblem mit Client/Server-Anwendung Netzwerkprogrammierung 20
S Server - Client Anwendung Netzwerkprogrammierung 3
K RMI macht Anwendung langsam? Netzwerkprogrammierung 8
G Performance einer verteilten RMI-Anwendung Netzwerkprogrammierung 4
R proxy für java anwendung angeben [resolved] Netzwerkprogrammierung 15

Ähnliche Java Themen

Neue Themen


Oben