Aralık yayını Blogumda sizlere Enterprise Network Management Platformu için kullandıgımız RMI Secure Login ve bu Platformda uyguladımız yaklaşımı sizlerlere aktarmak amacıyla duzenledim.
Bazı güvenlik ve Copyright sebeplerinden dolayı tüm kodu sizlerle paylaşayamacagım, fakat elimden geldigi kadar stub v örneklerle açıklayamaya çalısacagım.
İlk Olarak RMI Stub Interface lerimizi Kurmamız Lazım
Gördiginiz gibiInterfaceimize 3adet method vardır. getChallengeKey() Sever tarafıdan verilmis bir random String dir. Server bu String i Cachler ve client login olmaya çalıştıgında boyle bir keyi verp vemedimi diye bakar. Güvenlik için yarattıgınız keylerin validity periodu Yarım saati geçmemeli bu replay bazlı hacking in önune geçecektir.
public interface SecureRMILogin extends Remote {
public String getChallengeKey(String myID);
public String authenticate(String challenge,String signature, String alias);
public Object doSomeAction(String someKey, boolean force);
}
Elbette client herhangi bir SSL yardımı ile RMI Servere baglanmadıgı için Keyler plain Text olarak transfer edilmektedir ve Bu Keyler dışardan Networku dinleyen herhangi birisi tarafından kolaylıkla elde edilebilir ve Raplay Teknigi ile Kullanılabilir. Bu konuda daha fazla ayrıntılı bilgiyi gelecek blogumda sizlerle paylaşmaya çalışacagım. (RMI with Custom Socket Factory)
vede implementation olarak.
public class SecureRMILoginImpl extends UnicastRemoteObject implements SecureRMILogin{
......./Other Methods
/**
* Bu Method da ise Her Clienta ait unique bir challenge Key Yaratın mesela hostName+id+imestamp(MD5)ve bu ID yi dısarı aktarılmış ID listesine ekleyin bu ID yarım saat gecerli olmalı (ilk Kullanım icin )
* @return Challenge Key
*/
public String getChallengeKey(String myID){
........
return challengeKey;
}
/**
* Bu Method da kendinize ait bir SessionCredentials Class ı yaratın.
* ve erişmesi serbest olan tüm clientlar için bi Session ID,si
* yaratarak bir nevi Session Containerine aktarın.
* @return Session ID
*/
public String authenticate(String challenge,String signature, String alias){
PublicKey key = ....... //get your public Key
Signature signatureObj = Signature.getInstance(key.getAlgorithm());
signatureObj.initVerify(key);
signatureObj.update(buffer,0,buffer.length);
boolean allowed = signatureObjverify(signature);
if (allowed){
sessionID = ....... Unique Session ID Mechanism.
SessionCredentials credentials = new SessionCredentials(sessionID,challenge,signature,true);
sessions.put(sessionID, credentials); //Sessio mecanizması
}
return sessionID; //Clienta Yeni Session ID sini gonderin ve herhangi bir metodu cagırırken bu Session IDsini kullanıp authenticated oldugunuzu elirtin.
}
public boolean isAuthenticated(String sessionID){
if(sessions.containsKey(sessionID)){
return true;
}
return false;
}
public Object doSomeAction(String SessionID, String someAction, boolean force){
if (!isAuthenticated(sessionID))
{
throw new SecurityException("Method Call Denied");
}
..... Client is Authenticated .......
}
Sessionları tutmak icin HashMap Kullanablilirsiniz.
private HashMap<String, SessionCredentials > sessions = new HashMap<String, SessionCredentials>();
Elbette bu kısıma Session Timeout Mekanizmasınıda atmalısınız, eger client belirli (örnegin 30 Dakika gibi bir ) süre boyunca Baglantı kurmadıysa Session ID sini Invalidate etmelisiniz.
eger HashMap Kullanıyorsanız ayrı bir thread yaratıp her dakikada bir idle Sessionları kontrol edip HashMapten silebilirsiniz
@Override
public void run() {
super.run();
running = true;
while(running){
for(Iterator<String> e = hashMap.keySet().iterator(); e.hasNext();){
String key = e.next();
SessionCredentials credentials = hashMap.get(key);
.... Calculate Session Timeouts
}
}
}