~~Title: Einen SecurityManager implementieren~~ Ein SecurityManager wird benötigt wenn der Client bzw. ein Benutzer authentifiziert werden muss. In diesem Fall werden die Anmeldedaten vom Client an den Server übermittelt, damit dieser die Überprüfung durchführen kann. Der Server delegiert die Überpfürung der Daten stets an einen definierbaren SecurityManager. Wenn die Überprüfung der Daten erfolgreich war, kann der Client die Anmeldung abschließen. Im Fehlerfall wird eine detailierte Fehlerbeschreibung aufbereitet und angezeigt. Unser Ziel ist die Implementierung und Verwendung eines SecurityManagers. Die erlaubten Benutzer/Passwort Kombinationen werden dabei in einer Hashtable bereitgestellt. == Implementierung des SecurityManagers == Erstellen Sie die Server Klasse ''apps.firstapp.security.HashtableSecurityManager'' und implementieren Sie das Interface ''com.sibvisions.rad.server.security.ISecurityManager'' wie z.B.: /* * Copyright 2009 SIB Visions GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * * History * * 28.09.2009 - [JR] - creation */ package apps.firstapp.security; import java.util.Hashtable; import javax.rad.remote.IConnectionConstants; import javax.rad.server.ISession; import com.sibvisions.rad.server.security.ISecurityManager; /** * The HashtableSecurityManager is a {@link Hashtable} * based {@link ISecurityManager} implementation. * * @author René Jahn */ public class HashtableSecurityManager implements ISecurityManager { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class members //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** contains username/password mapping. */ private Hashtable htUsers = new Hashtable(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Initialization //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Creates a new instance of HashtableSecurityManager with * predefined users. */ public HashtableSecurityManager() { htUsers.put("username", "password"); htUsers.put("jvx", "jvx"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Interface implementation //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * {@inheritDoc} */ public synchronized void validateAuthentication(ISession pSession) { checkUser(pSession); } /** * {@inheritDoc} */ public synchronized void changePassword(ISession pSession) { checkUser(pSession); //check old password with current password! if (!htUsers.get(pSession.getUserName()).equals( pSession.getProperty(IConnectionConstants.OLDPASSWORD))) { throw new SecurityException("Invalid password"); } //user is valid -> change the password htUsers.put(pSession.getUserName(), (String)pSession.getProperty(IConnectionConstants.NEWPASSWORD)); } /** * {@inheritDoc} */ public synchronized void logout(ISession pSession) { } /** * {@inheritDoc} */ public synchronized IAccessController getAccessController(ISession pSession) { return null; } /** * {@inheritDoc} */ public synchronized void release() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // User-defined methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Checks if the user is known and the password is valid. * * @param pSession the session to authenticate */ private void checkUser(ISession pSession) { String sPwd = htUsers.get(pSession.getUserName()); if (sPwd == null) { throw new SecurityException("User not found!"); } if (!sPwd.equals(pSession.getPassword())) { throw new SecurityException("Invalid password"); } } } // HashtableSecurityManager Das Interface ''com.sibvisions.rad.server.security.ISecurityManager'' definiert die Methoden public void validateAuthentication(ISession pSession) throws Exception; public void changePassword(ISession pSession) throws Exception; public void logout(ISession pSession); public IAccessController getAccessController(ISession pSession); public void release(); Mit ''validateAuthentication'' wird geprüft ob der Benutzer vorhanden und ob das Passwort gültig ist. Wenn die Anmeldedaten ungültig sind oder die Anmeldung aus welchem Grund auch immer abgelehnt werden soll, muss eine beliebige Exception geworfen werden. Der Exception Text wird am Client übersetzt(falls nötig) und dem User angezeigt. Mit ''changePassword'' wird die Änderung des Passwortes durchgeführt. Sollte die Änderung fehlschlagen oder nicht erwünscht sein, muss eine beliebige Exception geworfen werden. Der Exception Text wird am Client übersetzt(falls nötig) und dem User angezeigt. Mit ''logout'' wird dem Security Manager mitgeteilt daß eine Sitzung beendet wurde. Die Beendigung kann entweder manuell, durch den Benutzer selbst, oder automatisch, durch den Ablauf eines Timeouts, durchgeführt werden. Mit ''getAccessController'' wird der Zugriff auf [[de:jvx:server:lco:lifecycle|Lifecycle Objekte]] eingeschränkt. Diese Methode wird beim Öffnen einer MasterConnection aufgerufen um die Zugriffe auf SubConnections bzw. SubSessions zu steuern. Beim Öffnen einer SubConnection wird mit IAccessController.isAllowed geprüft ob der Zugriff erlaubt ist. Mit ''release'' wird dem Security Manager mitgeteilt daß alle verwendeten Ressourcen freigegeben werden sollen. == Verwendung des SecurityManagers== Der SecurityManager muss in der Konfiguration (config.xml) der Applikation definiert werden, damit dieser beim nächsten Anmeldeversuch verwendet wird, z.B.: apps.firstapp.security.HashtableSecurityManager ... \\ **Note** Die Standard Konfiguration instanziiert den SecurityManager einmalig pro Applikation. Diese Instanz wird bei jedem Anmeldeversuch wiederverwendet. Daher ist es wichtig auf synchronized zu achten und das der Konstruktor keinen wesentlichen Code beinhaltet. Es ist auch möglich, den SecurityManager pro Session zu erzeugen, aber das muss konfiguriert werden.