[ZEPPELIN-6673] Capture notebook permission, authentication, and shell error-handling fixtures by xhaktm00 · Pull Request #5581 · apache/zeppelin · GitHub
Skip to content

[ZEPPELIN-6673] Capture notebook permission, authentication, and shell error-handling fixtures - #5581

Open
xhaktm00 wants to merge 8 commits into
apache:masterfrom
xhaktm00:ZEPPELIN-6673
Open

xhaktm00 wants to merge 8 commits into
apache:masterfrom
xhaktm00:ZEPPELIN-6673

Conversation

@xhaktm00

Copy link
Copy Markdown
Contributor

What is this PR for?

Capture how the server and the Angular shell behave around note permissions, sign-in and session expiry, so that ZEPPELIN-6727 can check its consumer against recorded behavior instead of rules copied from client code. This PR records behavior only. It does not change server, shell or Core code.

Recording. createLifecycleRecorder(metadata, { authentication: true }) also records /api/security/ticket, /api/login and /api/login/logout. Each redirect hop is recorded as its own request with its location and no body, and names the request it was redirected from in redirectedFrom, because logout cycles overlap and request order alone cannot pair them. A failed sign-in request becomes a failed record, while a failed notebook request still fails capture. writeWithoutAccountNames moves unchanged from read-fixtures.spec.ts (ZEPPELIN-6737) to lifecycle/capture.ts, so both capture specs replace account names with <user>.

Captures. notebook-auth-fixtures.spec.ts records 12 rows into e2e/fixtures/notebook-auth/ with a manifest, and notebook-auth-captures.test.mjs checks the inventory, provenance, redaction and each row's behavior. The shell rows are replayed through the production AppHttpInterceptor and AppMessageInterceptor.

Captured behavior

Fixture Behavior
acl-write.json Owner permission write 200, non-owner 403
acl-write-role-owner.json The same when the owner is named only by a role
acl-write-unauthenticated.json No session: 302 to /api/login, which answers 405
acl-write-anonymous.json Anonymous server: the write succeeds (200)
rest-401-logout.json Signed-in logout: 401 with no Location
rest-401-with-location.json Skipped, no file: this server never sends 401 with Location (needs an SSO realm such as Knox)
http-session-expired.json HTTP session expired while the WebSocket still works; one logout per 405 on a request that is not the logout
ws-global-auth-info.json AUTH_INFO without msgId; later reads on the same socket succeed
ws-global-error-info.json ERROR_INFO without msgId
ws-read-correlation.json Read failures carry their request msgId next to an unrelated global ERROR_INFO
ws-session-logout.json After a logout, a command on the old ticket is dropped; once the account signs in again it is answered with SESSION_LOGOUT (no msgId)
session-expiry-server-restart.json The same after a server restart

Points for review

  • Recorder contract change: location now survives header filtering in both fixture formats, reduced to its path (no host, query or path parameters; an unparseable value is dropped). failed records are accepted only in lifecycle captures, and lifecycle replay rejects a capture containing sign-in requests, failed records or location. The README is updated in the same PR, as in ZEPPELIN-6672 and ZEPPELIN-6737.
  • 401 with Location: with that row skipped, the shell's redirect branch is covered by a synthetic test that says so.
  • Restart row: after the in-test restart, the UI sign-in in global setup failed repeatedly on the restarted server. Starting a new server from the shell made it pass. The cause is not found; the README says to run the restart row last and restart the server from the shell before capturing again.
  • Read fixtures (ZEPPELIN-6737, recaptured from Apache master): the WebSocket messages and record counts are unchanged. Besides new IDs and timestamps, the permissions REST responses now arrive before the NOTE, ERROR_INFO and AUTH_INFO frames they used to follow. Order between REST and WebSocket is not defined, and the read replay passes.
  • Handoff table (README): "Behavior owner" is who handles the behavior (Server, Angular shell, Core). It is not metadata.owner, the package that keeps the capture. SESSION_LOGOUT belongs to the Angular shell (session foundation) and nothing handles it yet.
  • Pre-existing: read-fixtures.spec.ts:57 has a TypeScript conversion error that was hidden because that spec is not in the core-contract tsconfig. This PR does not add it there.

What type of PR is it?

Improvement

Todos

  • - Record sign-in requests and redirect hops in lifecycle captures behind an opt-in option
  • - Capture permission, authentication and session-expiry fixtures with an inventory test
  • - Replay the captured shell signals through the production interceptors
  • - Recapture the ZEPPELIN-6737 read fixtures from Apache master
  • - Document the capture procedure and the ZEPPELIN-6727 handoff

What is the Jira issue?

https://issues.apache.org/jira/browse/ZEPPELIN-6673

How should this be tested?

From zeppelin-web-angular:

npm run check:core-contract-fixtures  # 175 tests: 174 passed, 1 skipped (the 401 with Location row)
npm run test:shell                    # 318 passed

Breaking each new recorder and validation rule (18 changes), each inventory assertion against the captures (10 changes) and each interceptor branch the replay covers made a test fail. The "no reply in between" check of the SESSION_LOGOUT rows was confirmed only indirectly.

Captures were taken against Apache master bf658867be1067a208d3b41cd07cb0a3feb4ef06, built in a separate clone with capture/server.sh as the README describes:

  • authenticated (--mode auth): 11 supported, 1 skipped
  • anonymous: acl-write-anonymous.json
  • read fixtures: read-fixtures in anonymous and authenticated mode, both passed

Not run locally: npm run e2e:core-contract and the full E2E suite, Firefox and WebKit.

Screenshots (if appropriate)

Questions:

  • Does the license files need to update? No
  • Is there breaking changes for older versions? No. Recording without the new option is unchanged.
  • Does this needs documentation? The captures, the procedure and the handoff are documented in the core-contract README.

- Add an opt-in `authentication` option to the lifecycle recorder that also
  records /api/security/ticket, /api/login and /api/login/logout, keeps each
  redirect hop with its location and no body, and records a failed sign-in
  request as a `failed` record
- Keep only the path of a Location header in both formats and drop values that
  cannot be parsed
- Accept `failed` records only in lifecycle validation, with non-empty error text
- Reject captures with sign-in requests, failed records or a location header in
  lifecycle replay
- Document the contract change in the core-contract README
Signing in after a session expires starts several ticket checks whose
redirects overlap, so the order of records cannot tell which /api/login hop
came from which request. With the authentication option, a redirected
request now names the request it was redirected from in `redirectedFrom`,
and lifecycle validation requires that request to come earlier in the same
session.
Move writeWithoutAccountNames from the read fixture spec to the lifecycle
capture helpers so the authentication captures can mask account names the
same way. The read fixture spec only changes its imports.
Record permission writes by owner, non-owner, role owner, unauthenticated and
anonymous callers, a signed-in logout, an HTTP-only session expiry, global
AUTH_INFO and ERROR_INFO, read failures beside a global error, and
SESSION_LOGOUT after a logout and after a server restart. A REST 401 with a
Location is kept as a skipped row because this server never sends one.

The inventory test pins the fixture list, provenance and redaction, and checks
each row against the server and host behaviour it records.
A command sent on a ticket with no entry gets no reply, so the capture can only
show that it was dropped by waiting a quiet period. Mark both waits as the e2e
conventions require.
…erceptors

Drive the production AppHttpInterceptor and AppMessageInterceptor with the
notebook-auth captures:

- each captured 405 on a request that is not the logout starts one logout
- the captured logout 401 has no Location and leaves the page as it is;
  a synthetic 401 with Location covers the redirect the server never sends
- a global AUTH_INFO or ERROR_INFO is shown by the shell without changing
  the ticket
- SESSION_LOGOUT is left unhandled
…master

The read msgId change is now on Apache master, so read-anonymous.json and
read-denied.json are recaptured from bf65886
and name apache/zeppelin as their source.

The WebSocket messages and the record count are unchanged. Besides new IDs and
timestamps, the permissions REST responses now arrive before the NOTE,
ERROR_INFO and AUTH_INFO frames they used to follow. Order between REST and
WebSocket was never defined, and the read replay passes on both captures.
…7 handoff

Describe the notebook-auth fixtures, the two capture runs against the baseline
helper, and the sign-in failure seen after the in-test server restart, whose
cause is not yet known. The handoff table lists what a ZEPPELIN-6727 consumer
checks for each capture and who owns that behavior.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant