LoginLogout.lua 15 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
local _G = require "_G"
local assert = _G.assert
local error = _G.error
local ipairs = _G.ipairs
local pairs = _G.pairs
local pcall = _G.pcall
local type = _G.type
local coroutine = require "coroutine"
local string = require "string"
local io = require "io"
11
local uuid = require "uuid"
12 13 14
local giop = require "oil.corba.giop"
local cothread = require "cothread"
local openbus = require "openbus"
15
local libidl = require "openbus.idl"
16
local idl = require "openbus.core.idl"
17
local msg = require "openbus.util.messages"
18 19
local log = require "openbus.util.logger"

20 21
require "openbus.test.configs"

22
syskey = assert(openbus.readKeyFile(syskey))
23 24 25 26 27 28 29

local thread = coroutine.running()
local userdata = io.stdout
local sleep = cothread.delay

local sysex = giop.SystemExceptionIDs

30
local entity = nil -- defined later
31
local orb = openbus.initORB()
32 33
local OpenBusContext = orb.OpenBusContext
assert(OpenBusContext.orb == orb)
34 35 36 37 38 39 40 41 42 43
local conns = {}

local function catcherr(...)
  local ok, err = pcall(...)
  assert(not ok)
  return err
end

local callwithin do
  local function continuation(backup, ...)
44
    OpenBusContext:setCurrentConnection(backup)
45 46 47
    return ...
  end
  function callwithin(conn, func, ...)
48
    local backup = OpenBusContext:setCurrentConnection(conn)
49 50 51 52 53
    return continuation(backup, func(...))
  end
end

local loginways = {
54 55
  loginByPassword = function() return user, password end,
  loginByCertificate = function() return system, syskey end,
56
  loginBySharedAuth = function()
57 58 59 60
    return { -- dummy login process object
      login = function()
        return {
          id = "60D57646-33A4-4108-88DD-AE9B7A9E3C7A",
61
          entity = system,
62
        }, 1
63 64 65 66 67 68 69 70 71 72
      end,
      cancel = function () end,
    },
    "fake secret"
  end,
}
local function assertlogged(conn)
  -- check constant attributes
  assert(conn.orb == orb)
  -- check logged in only attributes
73
  assert(conn.login ~= nil)
74
  assert(conn.login.entity == entity)
75 76
  assert(uuid.isvalid(conn.login.id))
  assert(uuid.isvalid(conn.busid))
77 78 79 80 81
  local loginid = conn.login.id
  local busid = conn.busid
  -- check the attempt to login again
  for opname, getparams in pairs(loginways) do
    local ex = catcherr(conn[opname], conn, getparams())
82
    assert(ex._repid == libidl.types.AlreadyLoggedIn, ex)
83 84 85 86
    assert(conn.login.entity == entity)
    assert(conn.login.id == loginid)
    assert(conn.busid == busid)
  end
87 88
  -- check the failure of 'startSharedAuth'
  conn:cancelSharedAuth(conn:startSharedAuth())
89
  -- check the login is valid to perform calls
90 91 92
  local OfferRegistry = callwithin(conn, OpenBusContext.getOfferRegistry, OpenBusContext)
  assert(OfferRegistry ~= nil)
  callwithin(conn, OfferRegistry.findServices, OfferRegistry, {})
93 94 95
  return conn
end

96
local function assertlogoff(conn, invalid)
97 98 99 100
  -- check constant attributes
  assert(conn.orb == orb)
  -- check logged in only attributes
  assert(conn.login == nil)
101
  assert(conn.busid == nil)
102 103 104 105 106 107 108 109 110
  if not invalid then
    -- check the attempt to logoff again
    assert(conn:logout() == false)
    -- check the failure of 'startSharedAuth'
    local ex = catcherr(conn.startSharedAuth, conn)
    assert(ex._repid == sysex.NO_PERMISSION)
    assert(ex.completed == "COMPLETED_NO")
    assert(ex.minor == idl.const.services.access_control.NoLoginCode)
    -- check the login is invalid to perform calls
111
    local ex = callwithin(conn, catcherr, OpenBusContext.getOfferRegistry, OpenBusContext)
112 113 114 115
    assert(ex._repid == sysex.NO_PERMISSION)
    assert(ex.completed == "COMPLETED_NO")
    assert(ex.minor == idl.const.services.access_control.NoLoginCode)
  end
116 117 118 119 120 121 122 123
  return conn
end

log:TEST(true, "ConnectionManager::createConnection")

do log:TEST "connect with invalid host"
  for _, invalid in ipairs{true,false,123,{},error,thread,userdata} do
    local badtype = type(invalid)
124
    local ex = catcherr(OpenBusContext.createConnection, OpenBusContext, invalid, busport)
125 126 127 128 129 130 131
    assert(ex:match("bad argument #2 to 'createConnection' %(expected string, got "..badtype.."%)$"))
  end
end

do log:TEST "connect with invalid port"
  for _, invalid in ipairs{true,false,{},error,thread,userdata} do
    local badtype = type(invalid)
132
    local ex = catcherr(OpenBusContext.createConnection, OpenBusContext, bushost, invalid)
133 134 135 136 137 138 139
    assert(ex:match("bad argument #3 to 'createConnection' %(expected number|string, got "..badtype.."%)$"))
  end
end

do log:TEST "connect with invalid properties"
  for _, invalid in ipairs{true,false,123,"nolegacy",error,thread,userdata} do
    local badtype = type(invalid)
140
    local ex = catcherr(OpenBusContext.createConnection, OpenBusContext, bushost, busport, invalid)
141 142 143 144 145
    assert(ex:match("bad argument #4 to 'createConnection' %(expected nil|table, got "..badtype.."%)$"))
  end
end

do log:TEST "connect to unavailable host"
146 147 148 149 150 151
  local conn = OpenBusContext:createConnection("unavailable", busport)
  for op, params in pairs(loginways) do
    local ex = catcherr(conn[op], conn, params())
    assert(ex._repid == sysex.TRANSIENT)
    assert(ex.completed == "COMPLETED_NO")
  end
152 153 154
end

do log:TEST "connect to unavailable port"
155 156 157 158 159 160
  local conn = OpenBusContext:createConnection(bushost, 0)
  for op, params in pairs(loginways) do
    local ex = catcherr(conn[op], conn, params())
    assert(ex._repid == sysex.TRANSIENT)
    assert(ex.completed == "COMPLETED_NO")
  end
161 162
end

163 164 165 166 167 168 169
do log:TEST "password validator error"
  local conn = OpenBusContext:createConnection(bushost, busport)
  local ex = catcherr(conn.loginByPassword, conn, "error", "Oops!")
  assert(ex._repid == idl.types.services.ServiceFailure)
  assert(string.find(ex.message, "Oops!") ~= nil)
end

170 171
do log:TEST "connect to bus"
  for i = 1, 2 do
172
    conns[i] = assertlogoff(OpenBusContext:createConnection(bushost, busport))
173 174 175
  end
end

176 177 178
-- create a valid key to be used as a wrong key in the tests below.
-- the generation of this key is too time consuming and may delay the renewer
-- thread of the admin account to renew the admin login in time.
179
local WrongKey = openbus.newKey()
180 181
-- login as admin and provide additional functionality for the test
local invalidate, shutdown, leasetime do
182 183
  local orb = openbus.initORB()
  local OpenBusContext = orb.OpenBusContext
184
  local conn = OpenBusContext:createConnection(bushost, busport)
185
  conn:loginByPassword(admin, admpsw)
186
  OpenBusContext:setDefaultConnection(conn)
187 188
  leasetime = conn.AccessControl:renew()
  function invalidate(loginId)
189
    OpenBusContext:getLoginRegistry():invalidateLogin(loginId)
190 191 192
  end
  function shutdown()
    conn:logout()
193
    orb:shutdown()
194 195 196
  end
end

197
for _, connOp in ipairs({"DefaultConnection", "CurrentConnection"}) do
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
  local connIdx = 0
  repeat
    
    log:TEST(true, "Connection::loginBy* (",connOp,"=",connIdx==0 and "nil" or "conn"..connIdx,")")
    
    do log:TEST "login with invalid entity"
      local conn = conns[1]
      for _, invalid in ipairs{nil,true,false,123,{},error,thread,userdata} do
        local badtype = type(invalid)
        for _, op in ipairs{"loginByPassword", "loginByCertificate"} do
          local ex = catcherr(conn[op], conn, invalid, select(2, loginways[op]()))
          assert(ex:match("bad argument #1 to '"..op.."' %(expected string, got "..badtype.."%)$"))
          assertlogoff(conn)
        end
      end
    end
    
    do log:TEST "login with invalid password"
      local conn = conns[1]
      for _, invalid in ipairs{nil,true,false,123,{},error,thread,userdata} do
        local badtype = type(invalid)
219
        local ex = catcherr(conn.loginByPassword, conn, user, invalid)
220 221 222 223 224 225 226 227 228
        assert(ex:match("bad argument #2 to 'loginByPassword' %(expected string, got "..badtype.."%)$"))
        assertlogoff(conn)
      end
    end
    
    do log:TEST "login with invalid private key"
      local conn = conns[1]
      for _, invalid in ipairs{nil,true,false,123,"key",{},error,thread} do
        local badtype = type(invalid)
229
        local ex = catcherr(conn.loginByCertificate, conn, system, invalid)
230 231 232 233 234 235 236
        assert(ex:match("bad argument #2 to 'loginByCertificate' %(expected userdata, got "..badtype.."%)$"))
        assertlogoff(conn)
      end
    end
    
    do log:TEST "login with wrong password"
      local conn = conns[1]
237
      local ex = catcherr(conn.loginByPassword, conn, user, "WrongPassword")
238 239 240 241 242 243
      assert(ex._repid == idl.types.services.access_control.AccessDenied)
      assertlogoff(conn)
    end
    
    do log:TEST "login with entity without certificate"
      local conn = conns[1]
244
      local ex = catcherr(conn.loginByCertificate, conn, "NoCertif.", syskey)
245 246 247 248 249 250 251
      assert(ex._repid == idl.types.services.access_control.MissingCertificate)
      assert(ex.entity == "NoCertif.")
      assertlogoff(conn)
    end
    
    do log:TEST "login with wrong private key"
      local conn = conns[1]
252
      local ex = catcherr(conn.loginByCertificate, conn, system, WrongKey)
253
      assert(ex._repid == idl.types.services.access_control.AccessDenied)
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
      assertlogoff(conn)
    end
    
    do
      local function testlogin(conn, op, getparams)
        
        log:TEST("successful Connection::",op)
        if getparams == nil then getparams = loginways[op] end
        -- first login
        conn[op](conn, getparams())
        assertlogged(conn)
        local loginid = conn.login.id
        local busid = conn.busid
        -- first logout
        conn:logout()
        assertlogoff(conn)
        -- second login
        local function relogin()
          conn[op](conn, getparams())
          assertlogged(conn)
          assert(conn.login.id ~= loginid)
          assert(conn.busid == busid)
          loginid = conn.login.id
        end
        relogin()
        -- automatic login renew
        sleep(2*leasetime)
        assertlogged(conn)
        assert(conn.login.id == loginid)
        assert(conn.busid == busid)
        
        for otherIdx, other in ipairs(conns) do
          if other.login == nil then
            
288
            log:TEST(true, "Connection::loginBySharedAuth (from=Connection::",op,")")
289 290
            
            do log:TEST "login with wrong secret"
291 292
              local attempt = conn:startSharedAuth()
              local ex = catcherr(other.loginBySharedAuth, other, attempt, "WrongSecret")
293 294 295 296 297
              assert(ex._repid == idl.types.services.access_control.AccessDenied)
              assertlogoff(other)
              assertlogged(conn)
            end
            do log:TEST "login with canceled attempt"
298 299 300
              local attempt, secret = conn:startSharedAuth()
              conn:cancelSharedAuth(attempt)
              local ex = catcherr(other.loginBySharedAuth, other, attempt, secret)
301
              assert(ex._repid == libidl.types.InvalidLoginProcess)
302 303 304 305
              assertlogoff(other)
              assertlogged(conn)
            end
            do log:TEST "login with expired attempt"
306
              local attempt, secret = conn:startSharedAuth()
307
              sleep(2*leasetime)
308
              local ex = catcherr(other.loginBySharedAuth, other, attempt, secret)
309
              assert(ex._repid == libidl.types.InvalidLoginProcess)
310 311 312 313
              assertlogoff(other)
              assertlogged(conn)
            end
            do
314 315
              testlogin(other, "loginBySharedAuth", function()
                return conn:startSharedAuth()
316 317 318 319 320 321 322 323 324 325 326 327
              end)
              assertlogged(conn)
            end
            
            log:TEST(false)
            
            break
          end
        end
        
        log:TEST(true, "Connection::onInvalidLogin (how=",op,")")
        
328
        local OfferRegistry = callwithin(conn, OpenBusContext.getOfferRegistry, OpenBusContext)
329
        local called
330
        local function assertCallback(self, login)
331 332 333
          assert(self == conn)
          assert(login.id == loginid)
          assert(login.entity == entity)
334
          assertlogoff(conn, "invalid login")
335 336 337 338 339 340 341
          called = true
        end
        
        do log:TEST "become invalid"
          conn.onInvalidLogin = assertCallback
          -- during renew
          assert(called == nil)
342
          invalidate(conn.login.id)
343 344 345 346 347 348
          sleep(leasetime+2) -- wait renew
          assert(called); called = nil
          assertlogoff(conn)
          relogin()
          -- during call
          assert(called == nil)
349
          invalidate(conn.login.id)
350
          local ex = callwithin(conn, catcherr, OfferRegistry.findServices, OfferRegistry, {})
351 352
          assert(ex._repid == sysex.NO_PERMISSION)
          assert(ex.completed == "COMPLETED_NO")
353
          assert(ex.minor == idl.const.services.access_control.NoLoginCode)
354 355 356
          assert(called); called = nil
          assertlogoff(conn)
          relogin()
357 358 359 360 361 362 363
          -- during logout
          assert(called == nil)
          invalidate(conn.login.id)
          assert(conn:logout() == false)
          assert(called == nil)
          assertlogoff(conn)
          relogin()
364 365 366
        end
        
        do log:TEST "reconnect"
367 368 369 370
          function conn:onInvalidLogin(login)
            assertCallback(self, login)
            local ok, ex = pcall(relogin)
            if not ok then
371
              assert(ex._repid == libidl.types.AlreadyLoggedIn)
372 373
            end
            assertlogged(self)
374 375 376
          end
          -- during renew
          assert(called == nil)
377
          invalidate(conn.login.id)
378 379 380 381
          sleep(leasetime+2) -- wait renew
          assert(called); called = nil
          -- during call
          assert(called == nil)
382
          invalidate(conn.login.id)
383
          callwithin(conn, OfferRegistry.findServices, OfferRegistry, {})
384
          assert(called); called = nil
385 386 387 388 389 390 391
          -- during logout
          assert(called == nil)
          invalidate(conn.login.id)
          assert(conn:logout() == false)
          assert(called == nil)
          assertlogoff(conn)
          relogin()
392 393 394 395
        end
        
        do log:TEST "raise error"
          local raised = {"Oops!"}
396 397
          function conn:onInvalidLogin(login)
            assertCallback(self, login)
398 399 400 401
            error(raised)
          end
          -- during renew
          assert(called == nil)
402
          invalidate(conn.login.id)
403 404 405 406 407 408
          sleep(leasetime+2) -- wait renew
          assert(called); called = nil
          assertlogoff(conn)
          relogin()
          -- during call
          assert(called == nil)
409
          invalidate(conn.login.id)
410
          local ex = callwithin(conn, catcherr, OfferRegistry.findServices, OfferRegistry, {})
411 412 413
          assert(ex._repid == sysex.NO_PERMISSION)
          assert(ex.completed == "COMPLETED_NO")
          assert(ex.minor == idl.const.services.access_control.NoLoginCode)
414
          assert(called); called = nil
415 416 417 418 419 420 421 422
          assertlogoff(conn)
          relogin()
          -- during logout
          assert(called == nil)
          invalidate(conn.login.id)
          assert(conn:logout() == false)
          assert(called == nil)
          assertlogoff(conn)
423 424 425 426 427 428
        end
        
        log:TEST(false)
        
      end
      
429 430
      entity = user; testlogin(conns[1], "loginByPassword")
      entity = system; testlogin(conns[1], "loginByCertificate")
431 432 433 434
    end
    
    log:TEST(false)
    
435
    assert(OpenBusContext["get"..connOp](OpenBusContext) == conns[connIdx])
436 437
    connIdx = connIdx+1
    local nextConn = conns[connIdx]
438
    OpenBusContext["set"..connOp](OpenBusContext, nextConn)
439 440 441 442 443
  until nextConn == nil
end

log:TEST(false)

444
orb:shutdown()
445
shutdown()