blob: bd4ea2430c5d5596b28f91f66f5d784a6c3b1c52 [file] [log] [blame]
// $Id$
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
//
using System;
using Org.Apache.Etch.Bindings.Csharp.Msg;
using Org.Apache.Etch.Bindings.Csharp.Support;
using Org.Apache.Etch.Bindings.Csharp.Util;
namespace Org.Apache.Etch.Bindings.Csharp.Transport.Filter
{
/// <summary>
/// PwAuth is a message filter which watches for Session.UP and attempts to
/// authenticate the user by sending a message to the server with the name and
/// password in it. If the server responds, the session is notified with the
/// user name. If the server responds negatively, the session is notified of the
/// failure (using a PwAuthFail event). A transport control may also be sent to
/// force a login or logout or to set the name or password. The name and password
/// are initialized from the uri, or prompted for if not specified.
/// </summary>
public class PwAuth : AbstractMessageFilter
{
/// <summary>
/// client sessionQuery: return user name to use for authentication.
/// transportQuery: return the current user name (on server it has been validated).
/// client transportControl: set user name to use for authentication.
/// </summary>
public const String USER = "PwAuth.user";
/// <summary>
/// client sessionQuery: return password to use for authentication.
/// transportQuery: return the current password (on server it has been validated).
/// client transportControl: set password to use for authentication.
/// </summary>
///
public const String PASSWORD = "PwAuth.password";
/// <summary>
/// client transportControl: send authentication request
/// </summary>
private const String AUTHENTICATE = "PwAuth.authenticate";
public PwAuth(TransportMessage transport, URL uri, Resources resources)
: base(transport, uri, resources)
{
server = (Boolean)transport.TransportQuery(TransportConsts.IS_SERVER);
if (!server)
{
user = uri.User;
password = uri.Password;
}
// Log.report( "KeepAliveInstalled",
// "delay", delay, "count", count, "server", server );
vf = (ValueFactory)resources.Get(TransportConsts.VALUE_FACTORY);
mt_request = new XType("_Etch_PwAuthReq");
mt_response = new XType("_Etch_PwAuthResp");
vf.AddType(mt_request);
vf.AddType(mt_response);
mf_user = new Field("user");
mf_password = new Field("password");
mf_ok = new Field("ok");
mf_status = new Field("status");
mt_request.PutValidator(mf_user, Validator_string.Get(0));
mt_request.PutValidator(mf_password, Validator_string.Get(0));
mt_request.SetResult(mt_response);
mt_request.Lock();
mt_response.PutValidator(mf_ok, Validator_boolean.Get(0));
mt_response.PutValidator(mf_status, Validator_string.Get(0));
mt_response.Lock();
}
private String user;
private String password;
private readonly bool server;
private readonly ValueFactory vf;
private readonly Field mf_user;
private readonly Field mf_password;
private readonly Field mf_ok;
private readonly Field mf_status;
private readonly XType mt_request;
private readonly XType mt_response;
public bool GetServer()
{
return server;
}
public override bool SessionMessage(Who sender, Message msg)
{
if (msg.IsType(mt_request))
{
HandlePwAuthReq(sender, msg);
return true;
}
if (msg.IsType(mt_response))
{
HandlePwAuthResp(sender, msg);
return true;
}
return base.SessionMessage(sender, msg);
}
protected override bool SessionUp()
{
if (!server)
{
// client: send authentication request.
SendPwAuthReq();
}
return true;
}
protected override bool SessionDown()
{
if (server)
{
// make sure that server session's idea of user is cleared.
SessionNotifyUser(null, null);
}
return true;
}
private void SendPwAuthReq()
{
if (user == null)
{
user = (String)session.SessionQuery(USER);
if (user == null)
throw new Exception("PwAuth: user == null");
}
if (password == null)
{
password = (String)session.SessionQuery(PASSWORD);
if (password == null)
throw new Exception("PwAuth: password == null");
}
Message msg = new Message(mt_request, vf);
msg.Add(mf_user, user);
msg.Add(mf_password, password);
transport.TransportMessage(null, msg);
}
private void HandlePwAuthReq(Who sender, Message msg)
{
if (!server)
{
// we're a client that got a request, likely we're talking to a
// server that is confused.
return;
}
Console.WriteLine(" Sender: " + sender);
Console.WriteLine(" Message: " + msg);
String u = (String)msg.Get(mf_user);
String p = (String)msg.Get(mf_password);
try
{
OkStatus as1 = (OkStatus)SessionQuery(new UserPassword(u, p));
if (as1.ok)
SessionNotifyUser(u, p);
else
SessionNotifyUser(null, null);
sendPwAuthResp(sender, msg, as1.ok, as1.status);
}
catch (Exception e)
{
SessionNotifyUser(null, null);
sendPwAuthResp(sender, msg, false, e.ToString());
throw e;
}
}
private void sendPwAuthResp(Who recipient, Message msg, bool result, String status)
{
Message rmsg = msg.Reply();
rmsg.Add(mf_ok, result);
rmsg.Add(mf_status, status);
transport.TransportMessage(recipient, rmsg);
}
private void HandlePwAuthResp(Who sender, Message msg)
{
if (server)
{
// we're a server that got a response, likely we're talking to a
// client that is confused.
return;
}
// Log.report( "GotPwAuthResp", "sender", sender, "msg", msg );
bool result = (Boolean)msg.Get(mf_ok);
String status = (String)msg.Get(mf_status);
session.SessionNotify(new OkStatus(result, status));
}
public override object TransportQuery(Object query)
{
if ((string)query == USER)
return user;
if ((string)query == PASSWORD)
return password;
return base.TransportQuery(query);
}
public override void TransportControl(Object control, Object value)
{
if ((string)control == USER)
{
CheckNotServer();
user = (String)value;
return;
}
if ((string)control == PASSWORD)
{
CheckNotServer();
password = (String)value;
return;
}
if ((string)control == AUTHENTICATE)
{
CheckNotServer();
SendPwAuthReq();
return;
}
base.TransportControl(control, value);
}
private void CheckNotServer()
{
if (server)
throw new Exception("control not permitted by server");
}
private void SessionNotifyUser(String user, String password)
{
this.user = user;
this.password = password;
session.SessionNotify(new UserPassword(user, password));
}
/// <summary>
/// Server session query response to AuthUserPassword.
/// </summary>
public class OkStatus
{
/// <summary>Constructs the AuthOkStatus.</summary>
/// <param name="ok">true if user / password valid.</param>
/// <param name="status">message related to ok.</param>
public OkStatus(bool ok, String status)
{
this.ok = ok;
this.status = status;
}
public override String ToString()
{
return String.Format("AuthOkStatus( %s, %s )", ok, status);
}
// true if the user / password matched
public readonly bool ok;
// message related to ok
public readonly String status;
}
/// <summary>
/// Server session query to get AuthOkStatus, also server session event
/// to report changes in authentication status.
/// </summary>
public class UserPassword
{
/// <summary>Constructs the CheckAuth.</summary>
/// <param name="user">name to check</param>
/// <param name="password">password of the user</param>
public UserPassword(String user, String password)
{
this.user = user;
this.password = password;
}
public override String ToString()
{
return String.Format("AuthUserPassword( %s )", user);
}
// The user name to check
public readonly String user;
// The password of the user
public readonly String password;
}
public override string ToString()
{
return "PwAuth/" + transport;
}
}
}