CrimsonShadow
02-27-2011, 11:56 PM
I'm trying to do an encrypted login with some custom hashing of passwords and such but it seems like if I turn on encryption the hashId value on the client no longer matches the server side and the login is rejected as a result. I was able to reproduce the same behavior by modifying the LoginPasswordHashing example to change the client to enable encryption and wait for the encryption changed event before showing the login dialog. (Code copied below.)
Is this the intended behavior? Do I need to do something on the server side to compensate for an encrypted connection?
Thanks.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="onCreationComplete();" >
<mx:Script>
<![CDATA[
//ElectroServer imports
import com.electrotank.electroserver5.ElectroServer;
//ElectroServer message objects
import com.electrotank.electroserver5.api.ConnectionRespo nse;
import com.electrotank.electroserver5.api.LoginRequest;
import com.electrotank.electroserver5.api.LoginResponse;
import com.electrotank.electroserver5.api.MessageType;
import com.electrotank.electroserver5.api.EncryptionState ChangeEvent;
//For hashing the password
import com.electrotank.electroserver5.util.CryptoTools;
//Logger imports
import com.electrotank.electroserver5.util.ES5TraceAdapte r;
import com.electrotank.logging.adapter.Log;
import com.electrotank.logging.adapter.ILogger;
//Flash imports
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
//add this so we can see the logs get traced
Log.setLogAdapter(new ES5TraceAdapter());
private var _es:ElectroServer = new ElectroServer();
private var _hashId:int = 0;
private function onCreationComplete():void {
//remove the visual pieces we don't need yet
removeChild(loginPanel);
//load the connection settings, and connect
_es.loadAndConnect("settings.xml");
//listen for certain events to allow the application to flow, and to support chatting and user list updates
_es.engine.addEventListener(MessageType.Connection Response.name, onConnectionResponse);
_es.engine.addEventListener(MessageType.LoginRespo nse.name, onLoginResponse);
_es.engine.addEventListener(MessageType.Encryption StateChange.name, onEncryptionStateChangeResponse);
}
/**
* Fired when a connection to the server has either succeeded or failed.
*/
private function onConnectionResponse(e:ConnectionResponse):void {
if (e.successful) {
_hashId = e.hashId;
trace("Connection hashId: " + _hashId);
_es.engine.setEncryptionEnabled(true);
} else {
waitingField.text = "Connection failed!";
}
}
private function onEncryptionStateChangeResponse(event:EncryptionSt ateChangeEvent):void
{
//add the login panel so the user can login
removeChild(waitingPanel);
addChild(loginPanel);
}
/**
* Fired after the client has sent a login request, and the server has responded.
*/
private function onLoginResponse(e:LoginResponse):void {
if (e.successful) {
waitingField.text = "Logged in!";
} else {
waitingField.text = "Login failed!";
}
}
/**
* Called when the user clicks the 'submit' button on the login panel
*/
private function submitClicked():void {
//create a LoginRequest, and send it
var lr:LoginRequest = new LoginRequest();
lr.userName = userNameField.text;
lr.password = new CryptoTools().generatePasswordHash(passwordField.t ext, _hashId);
trace("LoginRequest: " + userNameField.text + ", " + _hashId + ", " + lr.password);
//Note: we do not set the hashId in the LoginRequest. That is done automatically.
_es.engine.send(lr);
removeChild(loginPanel);
addChild(waitingPanel);
}
]]>
</mx:Script>
<mx:Panel id="waitingPanel">
<mx:Text text="Please wait..." id="waitingField" />
</mx:Panel>
<mx:Panel title="Log in" id="loginPanel">
<mx:Form width="100%" height="100%">
<mx:FormItem label="User name" width="100%">
<mx:TextInput id="userNameField" width="100" />
</mx:FormItem>
<mx:FormItem label="Password" width="100%">
<mx:TextInput id="passwordField" width="100" />
</mx:FormItem>
</mx:Form>
<mx:ControlBar>
<mx:Button label="Submit" enabled="{userNameField.text.length > 0}" click="submitClicked();" />
</mx:ControlBar>
</mx:Panel>
</mx:Application>
Is this the intended behavior? Do I need to do something on the server side to compensate for an encrypted connection?
Thanks.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="onCreationComplete();" >
<mx:Script>
<![CDATA[
//ElectroServer imports
import com.electrotank.electroserver5.ElectroServer;
//ElectroServer message objects
import com.electrotank.electroserver5.api.ConnectionRespo nse;
import com.electrotank.electroserver5.api.LoginRequest;
import com.electrotank.electroserver5.api.LoginResponse;
import com.electrotank.electroserver5.api.MessageType;
import com.electrotank.electroserver5.api.EncryptionState ChangeEvent;
//For hashing the password
import com.electrotank.electroserver5.util.CryptoTools;
//Logger imports
import com.electrotank.electroserver5.util.ES5TraceAdapte r;
import com.electrotank.logging.adapter.Log;
import com.electrotank.logging.adapter.ILogger;
//Flash imports
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
//add this so we can see the logs get traced
Log.setLogAdapter(new ES5TraceAdapter());
private var _es:ElectroServer = new ElectroServer();
private var _hashId:int = 0;
private function onCreationComplete():void {
//remove the visual pieces we don't need yet
removeChild(loginPanel);
//load the connection settings, and connect
_es.loadAndConnect("settings.xml");
//listen for certain events to allow the application to flow, and to support chatting and user list updates
_es.engine.addEventListener(MessageType.Connection Response.name, onConnectionResponse);
_es.engine.addEventListener(MessageType.LoginRespo nse.name, onLoginResponse);
_es.engine.addEventListener(MessageType.Encryption StateChange.name, onEncryptionStateChangeResponse);
}
/**
* Fired when a connection to the server has either succeeded or failed.
*/
private function onConnectionResponse(e:ConnectionResponse):void {
if (e.successful) {
_hashId = e.hashId;
trace("Connection hashId: " + _hashId);
_es.engine.setEncryptionEnabled(true);
} else {
waitingField.text = "Connection failed!";
}
}
private function onEncryptionStateChangeResponse(event:EncryptionSt ateChangeEvent):void
{
//add the login panel so the user can login
removeChild(waitingPanel);
addChild(loginPanel);
}
/**
* Fired after the client has sent a login request, and the server has responded.
*/
private function onLoginResponse(e:LoginResponse):void {
if (e.successful) {
waitingField.text = "Logged in!";
} else {
waitingField.text = "Login failed!";
}
}
/**
* Called when the user clicks the 'submit' button on the login panel
*/
private function submitClicked():void {
//create a LoginRequest, and send it
var lr:LoginRequest = new LoginRequest();
lr.userName = userNameField.text;
lr.password = new CryptoTools().generatePasswordHash(passwordField.t ext, _hashId);
trace("LoginRequest: " + userNameField.text + ", " + _hashId + ", " + lr.password);
//Note: we do not set the hashId in the LoginRequest. That is done automatically.
_es.engine.send(lr);
removeChild(loginPanel);
addChild(waitingPanel);
}
]]>
</mx:Script>
<mx:Panel id="waitingPanel">
<mx:Text text="Please wait..." id="waitingField" />
</mx:Panel>
<mx:Panel title="Log in" id="loginPanel">
<mx:Form width="100%" height="100%">
<mx:FormItem label="User name" width="100%">
<mx:TextInput id="userNameField" width="100" />
</mx:FormItem>
<mx:FormItem label="Password" width="100%">
<mx:TextInput id="passwordField" width="100" />
</mx:FormItem>
</mx:Form>
<mx:ControlBar>
<mx:Button label="Submit" enabled="{userNameField.text.length > 0}" click="submitClicked();" />
</mx:ControlBar>
</mx:Panel>
</mx:Application>