LoginLogout.lua 17.1 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
local log = require "openbus.util.logger"
19
local util = require "openbus.util.server"
20

21
require "openbus.test.util"
22

23 24 25 26
setorbcfg(...)

busref = assert(util.readfrom(busref, "r"))
bus2ref = assert(util.readfrom(bus2ref, "r"))
27
syskey = assert(openbus.readKeyFile(syskey))
28 29 30 31 32 33 34

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

local sysex = giop.SystemExceptionIDs

35
local entity = nil -- defined later
36
local orb = openbus.initORB(orbcfg)
37 38
local OpenBusContext = orb.OpenBusContext
assert(OpenBusContext.orb == orb)
39
local conns = {}
40 41
local busid
local otherBusConn
42 43 44 45 46 47 48 49 50

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

local callwithin do
  local function continuation(backup, ...)
51
    OpenBusContext:setCurrentConnection(backup)
52 53 54
    return ...
  end
  function callwithin(conn, func, ...)
55
    local backup = OpenBusContext:setCurrentConnection(conn)
56 57 58 59 60
    return continuation(backup, func(...))
  end
end

local loginways = {
61
  loginByPassword = function() return user, password, domain end,
62
  loginByCertificate = function() return system, syskey end,
63
  loginBySharedAuth = function()
64 65 66 67 68 69 70 71 72 73 74 75
    return {
      busid = busid,
      attempt = { -- dummy login process object
        login = function()
          return {
            id = "60D57646-33A4-4108-88DD-AE9B7A9E3C7A",
            entity = system,
          }, 1
        end,
        cancel = function () end,
      },
      secret = "fake secret",
76
      cancel = function () end,
77
    }
78 79 80 81 82 83
  end,
}
local function assertlogged(conn)
  -- check constant attributes
  assert(conn.orb == orb)
  -- check logged in only attributes
84
  assert(conn.login ~= nil)
85
  assert(conn.login.entity == entity)
86 87
  assert(uuid.isvalid(conn.login.id))
  assert(uuid.isvalid(conn.busid))
88 89 90 91 92
  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())
93
    assert(ex._repid == libidl.types.AlreadyLoggedIn, ex)
94 95 96 97
    assert(conn.login.entity == entity)
    assert(conn.login.id == loginid)
    assert(conn.busid == busid)
  end
98
  -- check the failure of 'startSharedAuth'
99
  assert(conn:startSharedAuth():cancel() == true)
100
  -- check the login is valid to perform calls
101 102 103
  local OfferRegistry = callwithin(conn, OpenBusContext.getOfferRegistry, OpenBusContext)
  assert(OfferRegistry ~= nil)
  callwithin(conn, OfferRegistry.findServices, OfferRegistry, {})
104 105 106
  return conn
end

107
local function assertlogoff(conn, invalid)
108 109 110 111
  -- check constant attributes
  assert(conn.orb == orb)
  -- check logged in only attributes
  assert(conn.login == nil)
112
  assert(conn.busid == nil)
113 114
  if not invalid then
    -- check the attempt to logoff again
115
    assert(conn:logout() == true)
116 117 118 119 120 121
    -- 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
122
    local ex = callwithin(conn, catcherr, OpenBusContext.getOfferRegistry, OpenBusContext)
123 124 125 126
    assert(ex._repid == sysex.NO_PERMISSION)
    assert(ex.completed == "COMPLETED_NO")
    assert(ex.minor == idl.const.services.access_control.NoLoginCode)
  end
127 128 129
  return conn
end

130
log:TEST(true, "ConnectionManager::connectByAddress")
131 132 133 134

do log:TEST "connect with invalid host"
  for _, invalid in ipairs{true,false,123,{},error,thread,userdata} do
    local badtype = type(invalid)
135 136
    local ex = catcherr(OpenBusContext.connectByAddress, OpenBusContext, invalid, busport)
    assert(ex:match("bad argument #2 to 'connectByAddress' %(expected string, got "..badtype.."%)$"))
137 138 139 140 141 142
  end
end

do log:TEST "connect with invalid port"
  for _, invalid in ipairs{true,false,{},error,thread,userdata} do
    local badtype = type(invalid)
143 144
    local ex = catcherr(OpenBusContext.connectByAddress, OpenBusContext, bushost, invalid)
    assert(ex:match("bad argument #3 to 'connectByAddress' %(expected number|string, got "..badtype.."%)$"))
145 146 147 148 149 150
  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)
151 152
    local ex = catcherr(OpenBusContext.connectByAddress, OpenBusContext, bushost, busport, invalid)
    assert(ex:match("bad argument #4 to 'connectByAddress' %(expected nil|table, got "..badtype.."%)$"))
153 154 155 156
  end
end

do log:TEST "connect to unavailable host"
157
  local conn = OpenBusContext:connectByAddress("unavailable", busport)
158 159
  for op, params in pairs(loginways) do
    local ex = catcherr(conn[op], conn, params())
160
    if orbcfg and orbcfg.options.security == "required" then
161 162 163 164 165 166
      assert(ex._repid == sysex.NO_PERMISSION)
      assert(ex.completed == "COMPLETED_NO")
    else
      assert(ex._repid == sysex.TRANSIENT)
      assert(ex.completed == "COMPLETED_NO")
    end
167
  end
168 169 170
end

do log:TEST "connect to unavailable port"
171
  local conn = OpenBusContext:connectByAddress(bushost, 0)
172 173
  for op, params in pairs(loginways) do
    local ex = catcherr(conn[op], conn, params())
174
    if orbcfg and orbcfg.options.security == "required" then
175 176 177 178 179 180
      assert(ex._repid == sysex.NO_PERMISSION)
      assert(ex.completed == "COMPLETED_NO")
    else
      assert(ex._repid == sysex.TRANSIENT)
      assert(ex.completed == "COMPLETED_NO")
    end
181
  end
182 183
end

184
do log:TEST "password validator error"
185 186 187
  local bus = orb:newproxy(busref, nil, "::scs::core::IComponent")
  local conn = OpenBusContext:connectByReference(bus)
  local ex = catcherr(conn.loginByPassword, conn, "error", "Oops!", baddomain)
188 189 190 191
  assert(ex._repid == idl.types.services.ServiceFailure)
  assert(string.find(ex.message, "Oops!") ~= nil)
end

192
do log:TEST "connect to bus"
193 194
  local bus = orb:newproxy(busref, nil, "::scs::core::IComponent")
  local bus2 = orb:newproxy(bus2ref, nil, "::scs::core::IComponent")
195
  for i = 1, 2 do
196
    conns[i] = assertlogoff(OpenBusContext:connectByReference(bus))
197
  end
198
  otherBusConn = OpenBusContext:connectByReference(bus2)
199 200
end

201 202 203
-- 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.
204
local WrongKey = openbus.newKey()
205 206
-- login as admin and provide additional functionality for the test
local invalidate, shutdown, leasetime do
207
  local orb = openbus.initORB(orbcfg)
208
  local OpenBusContext = orb.OpenBusContext
209 210
  local busref = orb:newproxy(busref, nil, "::scs::core::IComponent")
  local conn = OpenBusContext:connectByReference(busref)
211
  conn:loginByPassword(admin, admpsw, domain)
212
  OpenBusContext:setDefaultConnection(conn)
213
  busid = conn.busid
214 215
  leasetime = conn.AccessControl:renew()
  function invalidate(loginId)
216
    OpenBusContext:getLoginRegistry():invalidateLogin(loginId)
217 218 219
  end
  function shutdown()
    conn:logout()
220
    orb:shutdown()
221 222 223
  end
end

224
for _, connOp in ipairs({"DefaultConnection", "CurrentConnection"}) do
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
  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)
246
        local ex = catcherr(conn.loginByPassword, conn, user, invalid, domain)
247 248 249 250 251
        assert(ex:match("bad argument #2 to 'loginByPassword' %(expected string, got "..badtype.."%)$"))
        assertlogoff(conn)
      end
    end
    
252 253 254 255 256 257 258 259 260 261
    do log:TEST "login with invalid domain"
      local conn = conns[1]
      for _, invalid in ipairs{nil,true,false,123,{},error,thread,userdata} do
        local badtype = type(invalid)
        local ex = catcherr(conn.loginByPassword, conn, user, password, invalid)
        assert(ex:match("bad argument #3 to 'loginByPassword' %(expected string, got "..badtype.."%)$"))
        assertlogoff(conn)
      end
    end
    
262 263 264 265
    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)
266
        local ex = catcherr(conn.loginByCertificate, conn, system, invalid)
267 268 269 270 271 272 273
        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]
274
      local ex = catcherr(conn.loginByPassword, conn, user, "WrongPassword", domain)
275 276 277 278
      assert(ex._repid == idl.types.services.access_control.AccessDenied)
      assertlogoff(conn)
    end
    
279 280 281 282 283 284 285
    do log:TEST "login with unknown domain"
      local conn = conns[1]
      local ex = catcherr(conn.loginByPassword, conn, user, password, "UnknownDomain")
      assert(ex._repid == idl.types.services.access_control.UnknownDomain)
      assertlogoff(conn)
    end
    
286 287
    do log:TEST "login with entity without certificate"
      local conn = conns[1]
288
      local ex = catcherr(conn.loginByCertificate, conn, "NoCertif.", syskey)
289 290 291 292 293 294 295
      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]
296
      local ex = catcherr(conn.loginByCertificate, conn, system, WrongKey)
297
      assert(ex._repid == idl.types.services.access_control.AccessDenied)
298 299 300 301 302 303 304 305 306 307 308 309 310 311
      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
312
        assert(conn:logout() == true)
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
        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
            
332
            log:TEST(true, "Connection::loginBySharedAuth (from=Connection::",op,")")
333 334
            
            do log:TEST "login with wrong secret"
335
              local attempt = conn:startSharedAuth()
336 337
              attempt.secret = "WrongSecret" -- this is not allowed by the API
              local ex = catcherr(other.loginBySharedAuth, other, attempt)
338 339 340 341 342
              assert(ex._repid == idl.types.services.access_control.AccessDenied)
              assertlogoff(other)
              assertlogged(conn)
            end
            do log:TEST "login with canceled attempt"
343 344 345
              local attempt = conn:startSharedAuth()
              attempt:cancel()
              local ex = catcherr(other.loginBySharedAuth, other, attempt)
346
              assert(ex._repid == libidl.types.InvalidLoginProcess)
347 348 349 350
              assertlogoff(other)
              assertlogged(conn)
            end
            do log:TEST "login with expired attempt"
351
              local attempt = conn:startSharedAuth()
352
              sleep(2*leasetime)
353
              local ex = catcherr(other.loginBySharedAuth, other, attempt)
354
              assert(ex._repid == libidl.types.InvalidLoginProcess)
355 356 357
              assertlogoff(other)
              assertlogged(conn)
            end
358
            do log:TEST "login with wrong bus"
359
              otherBusConn:loginByPassword(user, password, domain)
360 361 362 363 364 365 366
              local attempt = otherBusConn:startSharedAuth()
              assert(otherBusConn:logout() == true)
              local ex = catcherr(other.loginBySharedAuth, other, attempt)
              assert(ex._repid == libidl.types.WrongBus)
              assertlogoff(other)
              assertlogged(conn)
            end
367
            do
368 369
              testlogin(other, "loginBySharedAuth", function()
                return conn:startSharedAuth()
370 371 372 373 374 375 376 377 378 379 380 381
              end)
              assertlogged(conn)
            end
            
            log:TEST(false)
            
            break
          end
        end
        
        log:TEST(true, "Connection::onInvalidLogin (how=",op,")")
        
382
        local OfferRegistry = callwithin(conn, OpenBusContext.getOfferRegistry, OpenBusContext)
383
        local called
384
        local function assertCallback(self, login)
385 386 387
          assert(self == conn)
          assert(login.id == loginid)
          assert(login.entity == entity)
388
          assertlogoff(conn, "invalid login")
389 390 391 392 393 394 395
          called = true
        end
        
        do log:TEST "become invalid"
          conn.onInvalidLogin = assertCallback
          -- during renew
          assert(called == nil)
396
          invalidate(conn.login.id)
397 398 399 400 401 402
          sleep(leasetime+2) -- wait renew
          assert(called); called = nil
          assertlogoff(conn)
          relogin()
          -- during call
          assert(called == nil)
403
          invalidate(conn.login.id)
404
          local ex = callwithin(conn, catcherr, OfferRegistry.findServices, OfferRegistry, {})
405 406
          assert(ex._repid == sysex.NO_PERMISSION)
          assert(ex.completed == "COMPLETED_NO")
407
          assert(ex.minor == idl.const.services.access_control.NoLoginCode)
408 409 410
          assert(called); called = nil
          assertlogoff(conn)
          relogin()
411 412 413
          -- during logout
          assert(called == nil)
          invalidate(conn.login.id)
414
          assert(conn:logout() == true)
415 416 417
          assert(called == nil)
          assertlogoff(conn)
          relogin()
418 419 420
        end
        
        do log:TEST "reconnect"
421 422 423 424
          function conn:onInvalidLogin(login)
            assertCallback(self, login)
            local ok, ex = pcall(relogin)
            if not ok then
425
              assert(ex._repid == libidl.types.AlreadyLoggedIn)
426 427
            end
            assertlogged(self)
428 429 430
          end
          -- during renew
          assert(called == nil)
431
          invalidate(conn.login.id)
432 433 434 435
          sleep(leasetime+2) -- wait renew
          assert(called); called = nil
          -- during call
          assert(called == nil)
436
          invalidate(conn.login.id)
437
          callwithin(conn, OfferRegistry.findServices, OfferRegistry, {})
438
          assert(called); called = nil
439 440 441
          -- during logout
          assert(called == nil)
          invalidate(conn.login.id)
442
          assert(conn:logout() == true)
443 444 445
          assert(called == nil)
          assertlogoff(conn)
          relogin()
446 447 448 449
        end
        
        do log:TEST "raise error"
          local raised = {"Oops!"}
450 451
          function conn:onInvalidLogin(login)
            assertCallback(self, login)
452 453 454 455
            error(raised)
          end
          -- during renew
          assert(called == nil)
456
          invalidate(conn.login.id)
457 458 459 460 461 462
          sleep(leasetime+2) -- wait renew
          assert(called); called = nil
          assertlogoff(conn)
          relogin()
          -- during call
          assert(called == nil)
463
          invalidate(conn.login.id)
464
          local ex = callwithin(conn, catcherr, OfferRegistry.findServices, OfferRegistry, {})
465 466 467
          assert(ex._repid == sysex.NO_PERMISSION)
          assert(ex.completed == "COMPLETED_NO")
          assert(ex.minor == idl.const.services.access_control.NoLoginCode)
468
          assert(called); called = nil
469 470 471 472 473
          assertlogoff(conn)
          relogin()
          -- during logout
          assert(called == nil)
          invalidate(conn.login.id)
474
          assert(conn:logout() == true)
475 476
          assert(called == nil)
          assertlogoff(conn)
477 478 479 480 481 482
        end
        
        log:TEST(false)
        
      end
      
483 484
      entity = user; testlogin(conns[1], "loginByPassword")
      entity = system; testlogin(conns[1], "loginByCertificate")
485 486 487 488
    end
    
    log:TEST(false)
    
489
    assert(OpenBusContext["get"..connOp](OpenBusContext) == conns[connIdx])
490 491
    connIdx = connIdx+1
    local nextConn = conns[connIdx]
492
    OpenBusContext["set"..connOp](OpenBusContext, nextConn)
493 494 495 496 497
  until nextConn == nil
end

log:TEST(false)

498
orb:shutdown()
499
shutdown()