Main Page | Class Hierarchy | Class List | File List | Class Members

Diameter EAP Application API

Alpha Version

Author:
Yoshihiro Ohba
Date:
Created: January 12, 2004

Updated: June 23, 2004

Introduction

The libdiametereap library provides a C++ API to Diameter EAP (Extensible Authentication Protocol) Application. The library implements the specification defined in draft-ietf-aaa-eap-07.txt. This document describes the API.

Basic Features

The API has the following features.

Sample Program

Server Sample Program

/* BEGIN_COPYRIGHT                                                        */
/*                                                                        */
/* Open Diameter: Open-source software for the Diameter and               */
/*                Diameter related protocols                              */
/*                                                                        */
/* Copyright (C) 2002-2004 Open Diameter Project                          */
/*                                                                        */
/* This library is free software; you can redistribute it and/or modify   */
/* it under the terms of the GNU Lesser General Public License as         */
/* published by the Free Software Foundation; either version 2.1 of the   */
/* License, or (at your option) any later version.                        */
/*                                                                        */
/* This library is distributed in the hope that it will be useful,        */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
/* Lesser General Public License for more details.                        */
/*                                                                        */
/* You should have received a copy of the GNU Lesser General Public       */
/* License along with this library; if not, write to the Free Software    */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
/* USA.                                                                   */
/*                                                                        */
/* In addition, when you copy and redistribute some or the entire part of */
/* the source code of this software with or without modification, you     */
/* MUST include this copyright notice in each copy.                       */
/*                                                                        */
/* If you make any changes that are appeared to be useful, please send    */
/* sources that include the changed part to                               */
/* diameter-developers@lists.sourceforge.net so that we can reflect your  */
/* changes to one unified version of this software.                       */
/*                                                                        */
/* END_COPYRIGHT                                                          */

/* $Id: */
/* 
   server_test.cxx
   Server test program for Diameter EAP Application 
   Written by Yoshihiro Ohba
   Created December 23, 2003.
*/

/*
  ---------------------------------------------------------
  Brief explanation on what is done in this sample program.
  ---------------------------------------------------------

  This program includes the test for Diameter EAP application where
  EAP Identity method is performed either between a peer and a NAS
  (Case 1) or between the peer and a backend EAP server via the NAS
  (Case 2), and then EAP MD5-Challenge authenticator method is
  performed between the peer and the backend EAP server via the NAS.

  The peer session entity will prompt you to input a username.  Once
  the username is input, it is carried in an Response/Identity message
  and sent to the Diameter server.

  The NAS will retransmit the Request/Identity message until you input
  the username or the number of retransmission reaches its maximum
  value (the maximum value is set to 3 in this program).  For the
  latter case, the authenticator will stop its state machine and the
  peer will timeout and fail.

Case 1:

  Peer                NAS                         EAP Server
                     (= EAP PassThough          (= Diameter Server)
                        Authenticator +
                        Diameter client)         
   |                        |  Null message            |
   |                        |------------------------->|
   |                        |                          |
   |                        |  Request/Identity        |
   |  Request/Identity      |<-------------------------|
   |<-----------------------|                          |
   |                        |                          |
(input userid)              |                          |
   |                        |                          |
   |  Response/Identity     |                          |
   |----------------------->|  Response/Identity       |
   |                        |------------------------->|
   |                        |  Request/MD5-Challenge   |
   |  Request/MD5-Challenge |<-------------------------|
   |<-----------------------|                          |
   |  Response/MD5-Challenge|                          |
   |----------------------->|  Response/MD5-Challenge  |
   |                        |------------------------->|
   |                        |                          |
   |                        |          Success         |
   |       Success          |<-------------------------|
   |<-----------------------|

Case 2:

  Peer                NAS                         EAP Server
                     (= EAP PassThough          (= Diameter Server)
                        Authenticator +
                        Diameter client)         
   |  Request/Identity      |                          |
   |<-----------------------|                          |
   |                        |                          |
(input userid)              |                          |
   |                        |                          |
   |  Response/Identity     |                          |
   |----------------------->|  Response/Identity       |
   |                        |------------------------->|
   |                        |  Request/MD5-Challenge   |
   |  Request/MD5-Challenge |<-------------------------|
   |<-----------------------|                          |
   |  Response/MD5-Challenge|                          |
   |----------------------->|  Response/MD5-Challenge  |
   |                        |------------------------->|
   |                        |                          |
   |                        |          Success         |
   |       Success          |<-------------------------|
   |<-----------------------|

 */

#include <iostream>
#include <ace/Log_Msg.h>
#include <ace/OS.h>
#include "diameter_api.h"
#include "diameter_eap_server_session.hxx"
#include "eap.hxx"
#include "eap_peerfsm.hxx"
#include "eap_authfsm.hxx"
#include "eap_identity.hxx"
#include "eap_policy.hxx"
#include "eap_method_registrar.hxx"
#include "eap_fsm.hxx"
#include "eap_log.hxx"
#include "eap_md5.hxx"

typedef AAA_JobHandle<AAA_GroupedJob> MyJobHandle;

class MyBackendAuthSwitchStateMachine;

/******** Diameter EAP Client Session ********/

// Class definition for authenticator identity method for my application.
class MyEapAuthIdentityStateMachine : public EapAuthIdentityStateMachine
{
  friend class EapMethodStateMachineCreator<MyEapAuthIdentityStateMachine>;
public:
  MyEapAuthIdentityStateMachine(EapSwitchStateMachine &s)
    : EapAuthIdentityStateMachine(s) {} 

  // Reimplemented from EapAuthIdentityStateMachine.
  ProcessIdentityResult ProcessIdentity(std::string& identity) 
  {
    std::cout << "Identity received : " << identity << std::endl;
    return EapAuthIdentityStateMachine::Success;
  }
private:
  ~MyEapAuthIdentityStateMachine() {} 
};

// Class definition for authenticator MD5-Challenge method for my application.
class MyEapAuthMD5ChallengeStateMachine 
  : public EapAuthMD5ChallengeStateMachine
{
  friend class 
  EapMethodStateMachineCreator<MyEapAuthMD5ChallengeStateMachine>;
public:
  MyEapAuthMD5ChallengeStateMachine(EapSwitchStateMachine &s)
    : EapAuthMD5ChallengeStateMachine(s) {} 

  // Reimplemented from EapPeerMD5ChallengeStateMachine.
  void InputPassphrase() 
  {
    std::string &passphrase = Passphrase();
    passphrase.assign("abcd1234");
  }

private:
  ~MyEapAuthMD5ChallengeStateMachine() {} 
};

class MyBackendAuthSwitchStateMachine 
  : public EapBackendAuthSwitchStateMachine
{
 public:

  MyBackendAuthSwitchStateMachine(ACE_Reactor &r, MyJobHandle& h) 
    : EapBackendAuthSwitchStateMachine(r, h)
  {}

  void Send(AAAMessageBlock *b);

  void Success(AAAMessageBlock *b);

  void Success();

  void Failure(AAAMessageBlock *b);

  void Failure();

  void Abort();

 private:
};

class MyDiameterEapServerSession : public DiameterEapServerSession,
                                   public AAA_JobData
{
 public:
  MyDiameterEapServerSession(AAAApplicationCore& appCore, 
                             diameter_unsigned32_t appId=EapApplicationId) 
    : DiameterEapServerSession(appCore, appId),
      handle(EapJobHandle
             (AAA_GroupedJob::Create(appCore.GetTask().Job(), 
                                     this, "backend"))),
      eap(boost::shared_ptr<MyBackendAuthSwitchStateMachine>
          (new MyBackendAuthSwitchStateMachine
           (*appCore.GetTask().reactor(), handle))),
      identityMethod(EapContinuedPolicyElement(EapType(1))),
      md5Method(EapContinuedPolicyElement(EapType(4))),
      initial(true)
  {
    identityMethod.AddContinuedPolicyElement
      (&md5Method, EapContinuedPolicyElement::PolicyOnSuccess);
      
    eap->Policy().InitialPolicyElement(&identityMethod);

    eap->NeedInitialRequestToSend(false);

    this->Start();
  }

  void Start() throw(AAA_Error)
  { 
    DiameterEapServerSession::Start(); 
  }

  void Abort()
  {
    std::cout << "Diameter EAP server session aborted." << std::endl;
    DiameterEapServerSession::Stop();
    Eap().Stop();
  }

  MyBackendAuthSwitchStateMachine& Eap() { return *eap; }

  void ForwardEapResponse(std::string &eapMsg);

  bool ValidateUserName(const diameter_utf8string_t &userName)
  {
// Modified by Santiago Zapata Hernandez
// Old
#if 0
    if (userName == "ohba")
      return true;
    else
      return false;
#endif
// New
        return true;
// End New
  }

 private:
  EapJobHandle handle;
  boost::shared_ptr<MyBackendAuthSwitchStateMachine> eap;
  EapContinuedPolicyElement identityMethod;
  EapContinuedPolicyElement md5Method;
  bool initial;
};

// ----------------- Definition --------------
void MyBackendAuthSwitchStateMachine::Send(AAAMessageBlock *b)
  {
    std::cout << "EAP Request sent from backend authenticator" 
              << std::endl;
    std::string eapMsg(b->base(), b->length());
    JobData(Type2Type<MyDiameterEapServerSession>()).SignalContinue(eapMsg);
  }
void MyBackendAuthSwitchStateMachine::Success(AAAMessageBlock *b)
  {
    std::cout << "EAP Success sent from backend authenticator" 
              << std::endl;
    std::string eapMsg(b->base(), b->length());
    JobData(Type2Type<MyDiameterEapServerSession>()).SignalSuccess(eapMsg);
    Stop();
  }
void MyBackendAuthSwitchStateMachine::Success()
  {
    std::cout << "Success without an EAP Success" << std::endl;
    std::string eapMsg("");
    JobData(Type2Type<MyDiameterEapServerSession>()).SignalSuccess(eapMsg);
    Stop();
  }
void MyBackendAuthSwitchStateMachine::Failure(AAAMessageBlock *b)
  {
    std::cout << "EAP Failure sent from backend authenticator" 
              << std::endl;
    std::string eapMsg(b->base(), b->length());
    JobData(Type2Type<MyDiameterEapServerSession>()).SignalFailure(eapMsg);
    Stop();
  }
void MyBackendAuthSwitchStateMachine::Failure()
  {
    std::cout << "Failure without an EAP Failure" << std::endl;
    std::string eapMsg("");
    JobData(Type2Type<MyDiameterEapServerSession>()).SignalFailure(eapMsg);
    Stop();
  }
void MyBackendAuthSwitchStateMachine::Abort()
  {
    std::cout << "Session aborted for an error in state machine" << std::endl;
    Stop();
  }


void 
MyDiameterEapServerSession::ForwardEapResponse(std::string &eapMsg)
{
  std::cout << "EAP Response forwarded to backend authenticator" 
            << std::endl;
  AAAMessageBlock *msg;
  if (eapMsg.length() > 0)
    {
      msg = AAAMessageBlock::Acquire((ACE_UINT32)eapMsg.length());
      msg->copy((char*)eapMsg.data(), eapMsg.length());
      if (initial)
        {
          initial=false;
          Eap().Start(msg);    // The initial EAP-Response message.
        }
      else
        {
          Eap().Receive(msg);
        }
      msg->release();
    }
}

typedef AAAServerSessionClassFactory<MyDiameterEapServerSession> 
MyServerFactory;

class MyInitializer
{
 public:
  MyInitializer(AAAApplicationCore &appCore) 
    : applicationCore(appCore), 
      myAuthFactory(MyServerFactory(2000, AAA_STYPE_AUTHENTICATION))
  {
    Start();
  }

  ~MyInitializer() 
  {
    Stop();
  }

 private:

  void Start()
  {
    InitApplicationCore();
    InitEap();
    applicationCore.RegisterServerSessionFactory(&myAuthFactory);
  }

  void Stop() {}

  void InitApplicationCore()
  {
    ACE_DEBUG((LM_DEBUG, "[%N] Application starting\n"));
    if (applicationCore.Open() != AAA_ERR_SUCCESS)
      {
        ACE_ERROR((LM_ERROR, "[%N] Can't open configuraiton file."));
        exit(1);
      }
  }

  void InitEap()
  {
    ACE_DEBUG((LM_DEBUG, "[%N] EAP initialization.\n"));
    methodRegistrar.registerMethod
      (std::string("Identity"), EapType(1), 
       Authenticator, myAuthIdentityCreator);

    methodRegistrar.registerMethod
      (std::string("MD5-Challenge"), EapType(4), Authenticator, 
       myAuthMD5ChallengeCreator);
  }

  AAAApplicationCore &applicationCore;
  EapMethodRegistrar methodRegistrar;

  EapMethodStateMachineCreator<MyEapAuthMD5ChallengeStateMachine> 
  myAuthMD5ChallengeCreator;

  EapMethodStateMachineCreator<MyEapAuthIdentityStateMachine> 
  myAuthIdentityCreator;

  MyServerFactory myAuthFactory;
};

int
main(int argc, char *argv[])
{
  AAAApplicationCore applicationCore("config/server.local.xml");

  MyInitializer initializer(applicationCore);

  while (1) 
      ACE_OS::sleep(1);
  return 0;
}

Client Sample Program

/* BEGIN_COPYRIGHT                                                        */
/*                                                                        */
/* Open Diameter: Open-source software for the Diameter and               */
/*                Diameter related protocols                              */
/*                                                                        */
/* Copyright (C) 2002-2004 Open Diameter Project                          */
/*                                                                        */
/* This library is free software; you can redistribute it and/or modify   */
/* it under the terms of the GNU Lesser General Public License as         */
/* published by the Free Software Foundation; either version 2.1 of the   */
/* License, or (at your option) any later version.                        */
/*                                                                        */
/* This library is distributed in the hope that it will be useful,        */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
/* Lesser General Public License for more details.                        */
/*                                                                        */
/* You should have received a copy of the GNU Lesser General Public       */
/* License along with this library; if not, write to the Free Software    */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
/* USA.                                                                   */
/*                                                                        */
/* In addition, when you copy and redistribute some or the entire part of */
/* the source code of this software with or without modification, you     */
/* MUST include this copyright notice in each copy.                       */
/*                                                                        */
/* If you make any changes that are appeared to be useful, please send    */
/* sources that include the changed part to                               */
/* diameter-developers@lists.sourceforge.net so that we can reflect your  */
/* changes to one unified version of this software.                       */
/*                                                                        */
/* END_COPYRIGHT                                                          */

/* $Id: */
/* 
   client_test.cxx
   Client test program for Diameter EAP Application 
   Written by Yoshihiro Ohba
   Created December 5, 2003.
*/

/*
  ---------------------------------------------------------
  Brief explanation on what is done in this sample program.
  ---------------------------------------------------------

  This program includes the test for Diameter EAP application where
  EAP Identity method is performed either between a peer and a NAS,
  and then EAP MD5-Challenge authenticator method is performed between
  the peer and the backend EAP server via the NAS.

  The peer session entity will prompt you to input a username.  Once
  the username is input, it is carried in an Response/Identity message
  and sent to the Diameter server.

  The NAS will retransmit the Request/Identity message until you input
  the username or the number of retransmission reaches its maximum
  value (the maximum value is set to 3 in this program).  For the
  latter case, the authenticator will stop its state machine and the
  peer will timeout and fail.

  Peer                NAS                         EAP Server
                     (= EAP PassThough          (= Diameter Server)
                        Authenticator +
                        Diameter client)         
   |  Request/Identity      |                          |
   |<-----------------------|                          |
   |                        |                          |
(input userid)              |                          |
   |                        |                          |
   |  Response/Identity     |                          |
   |----------------------->|  Response/Identity       |
   |                        |------------------------->|
   |                        |  Request/MD5-Challenge   |
   |  Request/MD5-Challenge |<-------------------------|
   |<-----------------------|                          |
   |  Response/MD5-Challenge|                          |
   |----------------------->|  Response/MD5-Challenge  |
   |                        |------------------------->|
   |                        |                          |
   |                        |          Success         |
   |       Success          |<-------------------------|
   |<-----------------------|

 */

#include <iostream>
#include <ace/Log_Msg.h>
#include <ace/OS.h>
#include <ace/Atomic_Op_T.h>
#include "diameter_api.h"
#include "diameter_eap_client_session.hxx"
#include "eap.hxx"
#include "eap_peerfsm.hxx"
#include "eap_authfsm.hxx"
#include "eap_identity.hxx"
#include "eap_policy.hxx"
#include "eap_method_registrar.hxx"
#include "eap_fsm.hxx"
#include "eap_log.hxx"
#include "eap_md5.hxx"

ACE_Atomic_Op<ACE_Thread_Mutex, int> TotalSuccess;

typedef AAA_JobHandle<AAA_GroupedJob> MyJobHandle;

class MyPeerSwitchStateMachine;
class MyPassThroughAuthSwitchStateMachine;

class PeerData;
class PassThroughAuthApplication;

class EapTask : public AAA_Task
{
 public:
  EapTask() : AAA_Task(AAA_SCHED_FIFO, "EAP") 
  {}

  ~EapTask() {}
};

class Channel 
{
 public:
  Channel() {}
  virtual void Transmit(AAAMessageBlock *msg)=0;
  virtual void Transmit(AAAMessageBlock *msg, int subChannel)=0;
};


/******** Diameter EAP Client Session ********/

class MyDiameterEapClientSession : public DiameterEapClientSession
{
 public:
  MyDiameterEapClientSession(AAAApplicationCore& appCore, MyJobHandle h) 
    : DiameterEapClientSession(appCore, h)
  {}

  void Abort();

  void SignalContinue(std::string &eapMsg);

  void SignalSuccess(std::string &eapMsg);

  void SignalFailure(std::string &eapMsg);

  void SignalReauthentication();

  void SignalDisconnect() {}

  void SetDestinationRealm
  (AAA_ScholarAttribute<diameter_utf8string_t> &realm);

  void SetUserName(AAA_ScholarAttribute<diameter_utf8string_t> &username);
};

// Class definition for authenticator identity method for my application.
class MyEapAuthIdentityStateMachine : public EapAuthIdentityStateMachine
{
  friend class EapMethodStateMachineCreator<MyEapAuthIdentityStateMachine>;
public:
  MyEapAuthIdentityStateMachine(EapSwitchStateMachine &s)
    : EapAuthIdentityStateMachine(s) {} 

  // Reimplemented from EapAuthIdentityStateMachine.
  ProcessIdentityResult ProcessIdentity(std::string& identity) 
  {
    std::cout << "Identity received : " << identity << std::endl;
    return EapAuthIdentityStateMachine::Success;
  }
private:
  ~MyEapAuthIdentityStateMachine() {} 
};

// Class definition for peer MD5-Challenge method for my application.
class MyEapPeerMD5ChallengeStateMachine 
  : public EapPeerMD5ChallengeStateMachine
{
  friend class EapMethodStateMachineCreator<MyEapPeerMD5ChallengeStateMachine>;
public:
  MyEapPeerMD5ChallengeStateMachine(EapSwitchStateMachine &s)
    : EapPeerMD5ChallengeStateMachine(s) {} 

  // Reimplemented from EapPeerMD5ChallengeStateMachine.
  void InputPassphrase() 
  {
    std::string &passphrase = Passphrase();
    passphrase.assign("abcd1234");
  }
private:
  ~MyEapPeerMD5ChallengeStateMachine() {} 
};

// Class definition for authenticator MD5-Challenge method for my application.
class MyEapAuthMD5ChallengeStateMachine 
  : public EapAuthMD5ChallengeStateMachine
{
  friend class EapMethodStateMachineCreator<MyEapPeerMD5ChallengeStateMachine>;
public:
  MyEapAuthMD5ChallengeStateMachine(EapSwitchStateMachine &s)
    : EapAuthMD5ChallengeStateMachine(s) {} 

  // Reimplemented from EapPeerMD5ChallengeStateMachine.
  void InputPassphrase() 
  {
    std::string &passphrase = Passphrase();
    passphrase.assign("abcd1234");
  }

private:
  ~MyEapAuthMD5ChallengeStateMachine() {} 
};

class MyPeerSwitchStateMachine: public EapPeerSwitchStateMachine
{
 public:

  MyPeerSwitchStateMachine(ACE_Reactor &r, MyJobHandle& h) 
    : EapPeerSwitchStateMachine(r, h)
  {
    AuthPeriod() = 60;
  }

  void Send(AAAMessageBlock *b);

  void Success();

  void Failure();

  void Notification(std::string &str);

  void Abort();

  std::string& InputIdentity();

 private:

  std::string identity;
};

class MyPassThroughAuthSwitchStateMachine
  : public EapPassThroughAuthSwitchStateMachine
{
 public:

  MyPassThroughAuthSwitchStateMachine(ACE_Reactor &r, MyJobHandle& h) 
    : EapPassThroughAuthSwitchStateMachine(r, h)
  {}

  void Send(AAAMessageBlock *b);

  void Success(AAAMessageBlock *b);

  void Success();

  void Failure(AAAMessageBlock *b);

  void Failure();

  void Abort();

  void ForwardResponse(AAAMessageBlock *b);

 private:
};

class PeerChannel : public Channel
{
 public:
  PeerChannel(MyPeerSwitchStateMachine &s) : eap(s) {}
  void Transmit(AAAMessageBlock *msg) { eap.Receive(msg); }
  void Transmit(AAAMessageBlock *msg, int) {}
  MyPeerSwitchStateMachine &eap;
};

class PassThroughAuthChannel : public Channel
{
 public:
  PassThroughAuthChannel(MyPassThroughAuthSwitchStateMachine& s) : eap(s) {}

  void Transmit(AAAMessageBlock *msg) { eap.Receive(msg); }
  void Transmit(AAAMessageBlock *msg, int subChannel) 
  { 
    switch(subChannel)
      {
      case 1:
        eap.AAA_Continue(msg); 
        break;
      case 2:
        eap.AAA_Success(msg); 
        break;
      case 3:
        eap.AAA_Failure(msg); 
        break;
      }
  }
  MyPassThroughAuthSwitchStateMachine &eap;
};

class PeerApplication : public AAA_JobData
{
 public:
  PeerApplication(EapTask &task, ACE_Semaphore &sem) : 
    handle(MyJobHandle
           (AAA_GroupedJob::Create(task.Job(), this, "peer"))),
    eap(boost::shared_ptr<MyPeerSwitchStateMachine>
        (new MyPeerSwitchStateMachine(*task.reactor(), handle))),
    semaphore(sem),
    rxChannel(PeerChannel(*eap)),
    txChannel(0),
    md5Method(EapContinuedPolicyElement(EapType(4)))
  {
    eap->Policy().InitialPolicyElement(&md5Method);
    semaphore.acquire();
  }
  ~PeerApplication() 
  {}
  void Start(Channel *c)
  { 
    txChannel = c;
    eap->Start(); 
  }

  PeerChannel* RxChannel() { return &rxChannel; }

  Channel& TxChannel() { return *txChannel; }

  MyPeerSwitchStateMachine& Eap() { return *eap; }

  ACE_Semaphore& Semaphore() { return semaphore; }

 private:
  MyJobHandle handle;
  boost::shared_ptr<MyPeerSwitchStateMachine> eap;
  ACE_Semaphore &semaphore;
  PeerChannel rxChannel;
  Channel  *txChannel;
  EapContinuedPolicyElement md5Method;
};

// My application session (not used in this test program).
class NAS_Application : public AAA_JobData
{

 public:
  NAS_Application(EapTask &task, AAAApplicationCore& appCore,
                  ACE_Semaphore &sem, bool pickup=false)
    : handle(MyJobHandle
             (AAA_GroupedJob::Create(task.Job(), this, "NAS"))),
      diameter(boost::shared_ptr<MyDiameterEapClientSession>
               (new MyDiameterEapClientSession(appCore, handle))),
      eap(boost::shared_ptr<MyPassThroughAuthSwitchStateMachine>
          (new MyPassThroughAuthSwitchStateMachine
           (*task.reactor(), handle))),
      semaphore(sem),
      rxChannel(PassThroughAuthChannel(*eap)),
      peerTxChannel(0),
      method(EapContinuedPolicyElement(EapType(1)))
  {
    if (pickup)
      eap->Policy().InitialPolicyElement(&method);

    semaphore.acquire();
  }
  ~NAS_Application() {}

  void Start(Channel *c)
  { 
    peerTxChannel = c;
    diameter->Start(); 
    eap->RetransmissionInterval() = 5;

    eap->Start(); 
  }

  Channel* RxChannel() { return &rxChannel; }

  Channel& PeerTxChannel() { return *peerTxChannel; }

  MyPassThroughAuthSwitchStateMachine& Eap() { return *eap; }

  MyDiameterEapClientSession &Diameter() { return *diameter; }

  ACE_Semaphore& Semaphore() { return semaphore; }

 private:
  MyJobHandle handle;
  boost::shared_ptr<MyDiameterEapClientSession> diameter;
  boost::shared_ptr<MyPassThroughAuthSwitchStateMachine> eap;
  ACE_Semaphore &semaphore;
  PassThroughAuthChannel rxChannel;
  Channel *peerTxChannel;
  EapContinuedPolicyElement method;
};

// ----------------- Definition --------------
void MyPeerSwitchStateMachine::Send(AAAMessageBlock *b)
{
  std::cout << "EAP Response sent from peer" << std::endl;
  JobData(Type2Type<PeerApplication>()).TxChannel().Transmit(b);
}

void MyPeerSwitchStateMachine::Success()
  {
    TotalSuccess++;
    std::cout << "Authentication success detected at peer" << std::endl;
    std::cout << "Welcome to the world, " 
              << PeerIdentity() 
              << " !!! (" << TotalSuccess.value() << ")" << std::endl;
    Stop();
    JobData(Type2Type<PeerApplication>()).Semaphore().release();
  }
void MyPeerSwitchStateMachine::Failure()
  {
    std::cout << "Authentication failure detected at peer" << std::endl;
    std::cout << "Sorry, " 
              << PeerIdentity() 
              << " try next time !!!" << std::endl;
    Stop();
    JobData(Type2Type<PeerApplication>()).Semaphore().release();
  }
void MyPeerSwitchStateMachine::Notification(std::string &str)
  {
    std::cout << "Following notification received" << std::endl;
    std::cout << str << std::endl;
  }
void MyPeerSwitchStateMachine::Abort()
  {
    std::cout << "Peer aborted for an error in state machine" << std::endl;
    JobData(Type2Type<PeerApplication>()).Semaphore().release();
  }
std::string& MyPeerSwitchStateMachine::InputIdentity() 
  {
    identity = std::string("ohba");
#if 0
    std::cout << "Input username (within 10sec.): " << std::endl;
    std::cin >> identity;
    std::cout << "username = " << identity << std::endl;
#endif
    ACE_OS::sleep(2);
    return identity;
  }

void MyPassThroughAuthSwitchStateMachine::Send(AAAMessageBlock *b)
  {
    std::cout << "EAP Request sent from passthrough authenticator" 
              << std::endl;
    JobData(Type2Type<NAS_Application>()).PeerTxChannel().Transmit(b);
  }
void MyPassThroughAuthSwitchStateMachine::Success(AAAMessageBlock *b)
  {
    std::cout << "EAP Success sent from passthrough authenticator" 
              << std::endl;
    JobData(Type2Type<NAS_Application>()).PeerTxChannel().Transmit(b);
    Stop();
    JobData(Type2Type<NAS_Application>()).Semaphore().release();
  }
void MyPassThroughAuthSwitchStateMachine::Success()
  {
    std::cout << "Success without an EAP Success" << std::endl;
    Stop();
    JobData(Type2Type<NAS_Application>()).Semaphore().release();
  }
void MyPassThroughAuthSwitchStateMachine::Failure(AAAMessageBlock *b)
  {
    std::cout << "EAP Failure sent from passthrough authenticator" 
              << std::endl;
    JobData(Type2Type<NAS_Application>()).PeerTxChannel().Transmit(b);
    Stop();
    JobData(Type2Type<NAS_Application>()).Semaphore().release();
  }
void MyPassThroughAuthSwitchStateMachine::Failure()
  {
    std::cout << "Failure without an EAP Failure" << std::endl;
    Stop();
    JobData(Type2Type<NAS_Application>()).Semaphore().release();
  }
void MyPassThroughAuthSwitchStateMachine::Abort()
  {
    std::cout << "Session aborted for an error in state machine" << std::endl;
    Stop();
    JobData(Type2Type<NAS_Application>()).Diameter().Stop();
    JobData(Type2Type<NAS_Application>()).Semaphore().release();
  }
void MyPassThroughAuthSwitchStateMachine::ForwardResponse(AAAMessageBlock *b)
  {
    // if this is the first message from the peer, then create the
    // authenticator on the EAP server and start it.
    if (b)
        std::cout << "Passthrough authenticator is forwarding an EAP-Response "
                  << "to EAP server" << std::endl;
    else
        std::cout << "Passthrough authenticator is sending a null EAP message"
                  << "to EAP server to start EAP." << std::endl;

    std::string eapMsg;

    if (b)
      {
        std::cout << "Length = " << (unsigned)b->size() << std::endl;
        eapMsg.assign(b->base(), b->size());
      }

    JobData(Type2Type<NAS_Application>()).Diameter().ForwardResponse(eapMsg);
  }

void 
MyDiameterEapClientSession::Abort()
  {
    std::cout << "Diameter EAP client session aborted." << std::endl;
    DiameterEapClientSession::Stop();
    JobData(Type2Type<NAS_Application>()).Eap().Abort();
  }

void 
MyDiameterEapClientSession::SignalContinue(std::string &eapMsg)
  {
    AAAMessageBlock *msg 
      = AAAMessageBlock::Acquire((char*)eapMsg.data(), (ACE_UINT32)eapMsg.length());
    JobData(Type2Type<NAS_Application>()).Eap().AAA_Continue(msg);
    msg->Release();
  }

void 
MyDiameterEapClientSession::SignalSuccess(std::string &eapMsg)
  {
    AAAMessageBlock *msg = 0;
    if (eapMsg.length() > 0)
      {
        msg = AAAMessageBlock::Acquire((char*)eapMsg.data(), (ACE_UINT32)eapMsg.length());
      }

    JobData(Type2Type<NAS_Application>()).Eap().AAA_Success(msg);
    
    if (msg)
      msg->Release();
  }

void 
MyDiameterEapClientSession::SignalFailure(std::string &eapMsg)
  {
    AAAMessageBlock *msg = 0;
    if (eapMsg.length() > 0)
      msg = AAAMessageBlock::Acquire((char*)eapMsg.data(), (ACE_UINT32)eapMsg.length());
    else
      AAA_LOG(LM_DEBUG, "SignalFailure without EAP-Failure.\n");

    JobData(Type2Type<NAS_Application>()).Eap().AAA_Failure(msg);

    if (msg)
      msg->Release();
  }

void 
MyDiameterEapClientSession::SignalReauthentication()
  {
    JobData(Type2Type<NAS_Application>()).Eap().Restart();
  }

void
MyDiameterEapClientSession::SetDestinationRealm
(AAA_ScholarAttribute<diameter_utf8string_t> &realm)
{
  std::string& userName 
    = JobData(Type2Type<NAS_Application>()).Eap().PeerIdentity();

  size_t pos;

  if ((pos = userName.find('@')) != std::string::npos)
    realm.Set(std::string(userName, ++pos, userName.length() - pos));
  else
    realm.Set(std::string("research2.org"));
}

void
MyDiameterEapClientSession::SetUserName
(AAA_ScholarAttribute<diameter_utf8string_t> &username)
{
  std::string& userName 
    = JobData(Type2Type<NAS_Application>()).Eap().PeerIdentity();

  size_t pos;

  if ((pos = userName.find('@')) != std::string::npos)
    username.Set(std::string(userName.substr(pos)));
  else
    username = userName;
}

class MyInitializer
{
 public:
  MyInitializer(EapTask &t, AAAApplicationCore &appCore) 
    : task(t), applicationCore(appCore)
  {
    Start();
  }

  ~MyInitializer() 
  {
    Stop();
  }

 private:

  void Start()
  {
    InitEapTask();
    InitApplicationCore();
  }

  void Stop()
  {
    task.Stop();
  }

  void InitApplicationCore()
  {
    ACE_DEBUG((LM_DEBUG, "[%N] Application starting\n"));
    if (applicationCore.Open("config/client.local.xml",
                             &task) != AAA_ERR_SUCCESS)
      {
        ACE_ERROR((LM_ERROR, "[%N] Can't open configuraiton file."));
        exit(1);
      }
  }

  void InitEapTask()
  {
    ACE_DEBUG((LM_DEBUG, "[%N] EAP Task starting.\n"));
    methodRegistrar.registerMethod
      (std::string("Identity"), EapType(1), 
       Authenticator, myAuthIdentityCreator);

    methodRegistrar.registerMethod
      (std::string("MD5-Challenge"), EapType(4), Peer, 
       myPeerMD5ChallengeCreator);

    try {
      // Task starts with two threads in the thread pool.
      task.Start(10);
    }
    catch (...) {
      ACE_ERROR((LM_ERROR, "[%N]Task failed to start.\n"));
      exit(1);
    }
  }

  EapTask &task;
  AAAApplicationCore &applicationCore;
  EapMethodRegistrar methodRegistrar;

  EapMethodStateMachineCreator<MyEapPeerMD5ChallengeStateMachine> 
  myPeerMD5ChallengeCreator;

  EapMethodStateMachineCreator<MyEapAuthIdentityStateMachine> 
  myAuthIdentityCreator;
};

int
main(int argc, char *argv[])
{
  EapTask task;
  AAAApplicationCore applicationCore;
  MyInitializer initializer(task, applicationCore);

#if defined(WIN32)
  #define num 100
#else
  int num;
  std::cout << "Input number of sessions: ";
  std::cin >> num;
#endif
  ACE_Semaphore semaphore(2*num);

  TotalSuccess=0;

  std::auto_ptr<PeerApplication> peerApp[num];
  std::auto_ptr<NAS_Application> nasApp[num];
  for (int i=0; i<num; i++)
    {
      peerApp[i] 
        = std::auto_ptr<PeerApplication>(new PeerApplication(task, semaphore));
      nasApp[i] 
        = std::auto_ptr<NAS_Application>
        (new NAS_Application(task, applicationCore, semaphore, true));
      peerApp[i]->Start(nasApp[i]->RxChannel());
      nasApp[i]->Start(peerApp[i]->RxChannel());
    }

  // Block until the EAP conversation completes.
  for (int i=0; i<2*num; i++)
    semaphore.acquire();

  std::cout << "Total number of sessions : " << num << std::endl;
  std::cout << "Total number of success : " << TotalSuccess.value() << std::endl;

  for (int i=0; i<num; i++)
    {
      peerApp[i].reset();
      nasApp[i].reset();
    }
  return 0;
}


Generated on Fri Jun 25 19:14:21 2004 for Diameter EAP Application by doxygen 1.3.5