Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

163 строки
7.0KB

  1. <!-- #include file="../aspunit/Lib/ASPUnit.asp" -->
  2. <!-- #include file="../bootstrap.asp" -->
  3. <!-- #include file="../../core/lib.json.asp" -->
  4. <!-- #include file="../../core/lib.Keycloak.asp" -->
  5. <%
  6. Call ASPUnit.AddModule( _
  7. ASPUnit.CreateModule( _
  8. "Keycloak Callback Behavior Tests", _
  9. Array( _
  10. ASPUnit.CreateTest("EnsurePendingLoginValueCreatesNewValueWhenMissing"), _
  11. ASPUnit.CreateTest("EnsurePendingLoginValueReusesExistingValue"), _
  12. ASPUnit.CreateTest("HandleCallbackReturnsFalseWhenCodeIsMissing"), _
  13. ASPUnit.CreateTest("HandleCallbackSetsErrorMessageOnMissingCode"), _
  14. ASPUnit.CreateTest("StateValidationErrorExplainsMissingStoredState"), _
  15. ASPUnit.CreateTest("StateValidationErrorExplainsMismatchedStoredState"), _
  16. ASPUnit.CreateTest("IsLoggedInReturnsFalseWithEmptySession"), _
  17. ASPUnit.CreateTest("IsLoggedInReturnsTrueWhenTokenStoredInSession"), _
  18. ASPUnit.CreateTest("ClearSessionRemovesStoredTokens") _
  19. ), _
  20. ASPUnit.CreateLifeCycle("SetupKeycloakCallbackBehavior", "TeardownKeycloakCallbackBehavior") _
  21. ) _
  22. )
  23. Call ASPUnit.Run()
  24. Sub SetupKeycloakCallbackBehavior()
  25. Call ResetTestRuntime()
  26. KeycloakAuth_Class__Singleton = Empty
  27. Session.Contents.Remove "Keycloak_AccessToken"
  28. Session.Contents.Remove "Keycloak_RefreshToken"
  29. Session.Contents.Remove "Keycloak_IdToken"
  30. Session.Contents.Remove "Keycloak_State"
  31. Session.Contents.Remove "Keycloak_Nonce"
  32. Session.Contents.Remove "Keycloak_UserInfoJson"
  33. End Sub
  34. Sub TeardownKeycloakCallbackBehavior()
  35. Session.Contents.Remove "Keycloak_AccessToken"
  36. Session.Contents.Remove "Keycloak_RefreshToken"
  37. Session.Contents.Remove "Keycloak_IdToken"
  38. Session.Contents.Remove "Keycloak_State"
  39. Session.Contents.Remove "Keycloak_Nonce"
  40. Session.Contents.Remove "Keycloak_UserInfoJson"
  41. KeycloakAuth_Class__Singleton = Empty
  42. Call ResetTestRuntime()
  43. End Sub
  44. ' Builds a configured KeycloakAuth_Class instance for callback behavior tests
  45. Function NewCallbackTestAuth()
  46. Dim auth
  47. Set auth = New KeycloakAuth_Class
  48. Call auth.Configure("https://login.example.test/", "survey", "classic-app", "secret", "https://app.example.test/auth/callback")
  49. auth.LogoutRedirectUri = "https://app.example.test/"
  50. Set NewCallbackTestAuth = auth
  51. End Function
  52. ' A fresh login should create a new pending value in Session so the redirect can
  53. ' include state/nonce even when the session starts empty.
  54. Function EnsurePendingLoginValueCreatesNewValueWhenMissing()
  55. Dim auth, value
  56. Set auth = NewCallbackTestAuth()
  57. Session.Contents.Remove "Keycloak_State"
  58. value = auth.EnsurePendingLoginValue("Keycloak_State")
  59. Call ASPUnit.Ok(Len(value) > 0, "EnsurePendingLoginValue should create a value when the session does not have one")
  60. Call ASPUnit.Equal(Session("Keycloak_State"), value, "EnsurePendingLoginValue should store the created value in Session")
  61. End Function
  62. ' Repeated hits to /auth/login in the same session should keep using the same
  63. ' pending state instead of overwriting it and breaking the first callback.
  64. Function EnsurePendingLoginValueReusesExistingValue()
  65. Dim auth, value
  66. Set auth = NewCallbackTestAuth()
  67. Session("Keycloak_State") = "existing-state-123"
  68. value = auth.EnsurePendingLoginValue("Keycloak_State")
  69. Call ASPUnit.Equal(value, "existing-state-123", "EnsurePendingLoginValue should reuse an existing pending value")
  70. Call ASPUnit.Equal(Session("Keycloak_State"), "existing-state-123", "EnsurePendingLoginValue should not overwrite an existing session value")
  71. End Function
  72. ' HandleCallback returns False when the request has no 'code' query parameter
  73. ' (the typical outcome of a direct navigation or an incomplete redirect)
  74. Function HandleCallbackReturnsFalseWhenCodeIsMissing()
  75. Dim auth, result
  76. Set auth = NewCallbackTestAuth()
  77. result = auth.HandleCallback()
  78. Call ASPUnit.Ok(Not CBool(result), "HandleCallback should return False when no authorization code is present in the request")
  79. End Function
  80. ' HandleCallback must describe the failure in ErrorMessage so the view
  81. ' can surface a meaningful message to the user
  82. Function HandleCallbackSetsErrorMessageOnMissingCode()
  83. Dim auth
  84. Set auth = NewCallbackTestAuth()
  85. Call auth.HandleCallback()
  86. Call ASPUnit.Ok( _
  87. InStr(LCase(auth.ErrorMessage), "authorization code") > 0, _
  88. "HandleCallback should set an error message mentioning 'authorization code' when the code parameter is absent" _
  89. )
  90. End Function
  91. ' IsLoggedIn reflects the presence of an access token in the Session —
  92. ' no token means not logged in
  93. Function IsLoggedInReturnsFalseWithEmptySession()
  94. Dim auth
  95. Set auth = NewCallbackTestAuth()
  96. Call ASPUnit.Ok(Not auth.IsLoggedIn(), "IsLoggedIn should return False when no access token is stored in session")
  97. End Function
  98. ' Placing a token in the Session should cause IsLoggedIn to return True
  99. ' without any HTTP call — the session IS the auth state
  100. Function IsLoggedInReturnsTrueWhenTokenStoredInSession()
  101. Dim auth
  102. Set auth = NewCallbackTestAuth()
  103. Session("Keycloak_AccessToken") = "eyJ.test.token"
  104. Call ASPUnit.Ok(auth.IsLoggedIn(), "IsLoggedIn should return True when an access token is present in session")
  105. End Function
  106. ' ClearSession must remove all Keycloak_ prefixed keys so that a subsequent
  107. ' IsLoggedIn check correctly reports the user as signed out
  108. Function ClearSessionRemovesStoredTokens()
  109. Dim auth
  110. Set auth = NewCallbackTestAuth()
  111. Session("Keycloak_AccessToken") = "eyJ.test.token"
  112. Session("Keycloak_RefreshToken") = "eyJ.refresh.token"
  113. Call auth.ClearSession()
  114. Call ASPUnit.Ok(Not auth.IsLoggedIn(), "ClearSession should remove stored tokens so IsLoggedIn returns False")
  115. End Function
  116. ' When the stored login state is absent, the callback failure should point to
  117. ' session loss, callback reload, or direct navigation instead of a generic
  118. ' mismatch so troubleshooting is faster.
  119. Function StateValidationErrorExplainsMissingStoredState()
  120. Dim auth, message
  121. Set auth = NewCallbackTestAuth()
  122. message = auth.StateValidationError("callback-state-123")
  123. Call ASPUnit.Ok( _
  124. InStr(LCase(message), "stored session state is missing") > 0, _
  125. "StateValidationError should explain when the stored session state is missing" _
  126. )
  127. End Function
  128. ' When a session state exists but differs from the callback state, the helper
  129. ' should describe a stale callback or overlapping login rather than session loss.
  130. Function StateValidationErrorExplainsMismatchedStoredState()
  131. Dim auth, message
  132. Set auth = NewCallbackTestAuth()
  133. Session("Keycloak_State") = "expected-state-123"
  134. message = auth.StateValidationError("callback-state-456")
  135. Call ASPUnit.Ok( _
  136. InStr(LCase(message), "did not match the active login session") > 0 And InStr(LCase(message), "another login attempt") > 0, _
  137. "StateValidationError should explain when the callback state differs from the stored login state" _
  138. )
  139. End Function
  140. %>

Powered by TurnKey Linux.