janhoy commented on code in PR #1791:
URL: https://github.com/apache/solr/pull/1791#discussion_r1296130713


##########
solr/webapp/web/js/angular/controllers/login.js:
##########
@@ -60,92 +60,169 @@ solrAdminApp.controller('LoginController',
             var hp = AuthenticationService.decodeHashParams(hash);
             var expectedState = sessionStorage.getItem("auth.stateRandom") + 
"_" + sessionStorage.getItem("auth.location");
             sessionStorage.setItem("auth.state", "error");
-            if (hp['access_token'] && hp['token_type'] && hp['state']) {
-              // Validate state
-              if (hp['state'] !== expectedState) {
-                $scope.error = "Problem with auth callback";
-                console.log("Expected state param " + expectedState + " but 
got " + hp['state']);
-                errorText += "Invalid values in state parameter. ";
-              }
-              // Validate token type
-              if (hp['token_type'].toLowerCase() !== "bearer") {
-                console.log("Expected token_type param 'bearer', but got " + 
hp['token_type']);
-                errorText += "Invalid values in token_type parameter. ";
-              }
-              // Unpack ID token and validate nonce, get username
-              if (hp['id_token']) {
-                var idToken = hp['id_token'].split(".");
-                if (idToken.length === 3) {
-                  var payload = 
AuthenticationService.decodeJwtPart(idToken[1]);
-                  if (!payload['nonce'] || payload['nonce'] !== 
sessionStorage.getItem("auth.nonce")) {
-                    errorText += "Invalid 'nonce' value, possible attack 
detected. Please log in again. ";
-                  }
+            $scope.authData = AuthenticationService.getAuthDataHeader();
+            if (!validateState(hp['state'], expectedState)) {
+              $scope.error = "Problems with OpenID callback";
+              $scope.errorDescription = errorText;
+              $scope.http401 = "true";
+              sessionStorage.setItem("auth.state", "error");
+            }
+            else {
+              // for backward compatibility default flow to 'implicit'
+              var flow = $scope.authData ? 
$scope.authData['authorization_flow'] : "implicit";
+              console.log("Callback: authorization_flow : " +flow);
+              var isCodePKCE = flow == 'code_pkce';
+              if (isCodePKCE) {
+                // code flow with PKCE
+                console.debug("Callback. Using code flow with PKCE");
+                var code = hp['code'];
+                var tokenEndpoint = $scope.authData['tokenEndpoint'];
+                // concurrent Solr API calls will trigger 401 and erase 
session's "auth.realm" in app.js
+                // save it before it's erased
+                var authRealm = sessionStorage.getItem("auth.realm");
+
+                var data = {
+                  'grant_type': 'authorization_code',
+                  'code': code,
+                  'redirect_uri': $window.location.href.split('#')[0],
+                  'scope': "openid " + $scope.authData['scope'],
+                  'code_verifier': sessionStorage.getItem('codeVerifier'),
+                  "client_id": $scope.authData['client_id']
+                };
 
-                  if (errorText === "") {
-                    sessionStorage.setItem("auth.username", payload['sub']);
-                    sessionStorage.setItem("auth.header", "Bearer " + 
hp['access_token']);
-                    sessionStorage.removeItem("auth.statusText");
-                    sessionStorage.removeItem("auth.stateRandom");
-                    sessionStorage.removeItem("auth.wwwAuthHeader");
-                    console.log("User " + payload['sub'] + " is logged in");
-                    var redirectTo = sessionStorage.getItem("auth.location");
-                    console.log("Redirecting to stored location " + 
redirectTo);
-                    sessionStorage.setItem("auth.state", "authenticated");
-                    sessionStorage.removeItem("http401");
-                    $location.path(redirectTo).hash("");
+                console.debug(`Callback. Got code: ${code} \nCalling token 
endpoint:: ${tokenEndpoint} `);
+                AuthenticationService.getOAuthTokens(tokenEndpoint, 
data).then(function(response) {

Review Comment:
   > One outstanding question is: how can we incorporate the /token URL into 
the list of allowed URLs in the CSP connect-src directive? For now, this is 
manually added in server/etc/jetty.xml.’
   
   Yea, we need backend to be able to generate CSP header dynamically (now it 
is set statically in `jetty.xml`). Let's explore that.



##########
solr/webapp/web/js/angular/controllers/login.js:
##########
@@ -60,92 +60,169 @@ solrAdminApp.controller('LoginController',
             var hp = AuthenticationService.decodeHashParams(hash);
             var expectedState = sessionStorage.getItem("auth.stateRandom") + 
"_" + sessionStorage.getItem("auth.location");
             sessionStorage.setItem("auth.state", "error");
-            if (hp['access_token'] && hp['token_type'] && hp['state']) {
-              // Validate state
-              if (hp['state'] !== expectedState) {
-                $scope.error = "Problem with auth callback";
-                console.log("Expected state param " + expectedState + " but 
got " + hp['state']);
-                errorText += "Invalid values in state parameter. ";
-              }
-              // Validate token type
-              if (hp['token_type'].toLowerCase() !== "bearer") {
-                console.log("Expected token_type param 'bearer', but got " + 
hp['token_type']);
-                errorText += "Invalid values in token_type parameter. ";
-              }
-              // Unpack ID token and validate nonce, get username
-              if (hp['id_token']) {
-                var idToken = hp['id_token'].split(".");
-                if (idToken.length === 3) {
-                  var payload = 
AuthenticationService.decodeJwtPart(idToken[1]);
-                  if (!payload['nonce'] || payload['nonce'] !== 
sessionStorage.getItem("auth.nonce")) {
-                    errorText += "Invalid 'nonce' value, possible attack 
detected. Please log in again. ";
-                  }
+            $scope.authData = AuthenticationService.getAuthDataHeader();
+            if (!validateState(hp['state'], expectedState)) {
+              $scope.error = "Problems with OpenID callback";
+              $scope.errorDescription = errorText;
+              $scope.http401 = "true";
+              sessionStorage.setItem("auth.state", "error");
+            }
+            else {
+              // for backward compatibility default flow to 'implicit'
+              var flow = $scope.authData ? 
$scope.authData['authorization_flow'] : "implicit";
+              console.log("Callback: authorization_flow : " +flow);
+              var isCodePKCE = flow == 'code_pkce';
+              if (isCodePKCE) {
+                // code flow with PKCE
+                console.debug("Callback. Using code flow with PKCE");
+                var code = hp['code'];
+                var tokenEndpoint = $scope.authData['tokenEndpoint'];
+                // concurrent Solr API calls will trigger 401 and erase 
session's "auth.realm" in app.js
+                // save it before it's erased
+                var authRealm = sessionStorage.getItem("auth.realm");
+
+                var data = {
+                  'grant_type': 'authorization_code',
+                  'code': code,
+                  'redirect_uri': $window.location.href.split('#')[0],
+                  'scope': "openid " + $scope.authData['scope'],
+                  'code_verifier': sessionStorage.getItem('codeVerifier'),
+                  "client_id": $scope.authData['client_id']
+                };
 
-                  if (errorText === "") {
-                    sessionStorage.setItem("auth.username", payload['sub']);
-                    sessionStorage.setItem("auth.header", "Bearer " + 
hp['access_token']);
-                    sessionStorage.removeItem("auth.statusText");
-                    sessionStorage.removeItem("auth.stateRandom");
-                    sessionStorage.removeItem("auth.wwwAuthHeader");
-                    console.log("User " + payload['sub'] + " is logged in");
-                    var redirectTo = sessionStorage.getItem("auth.location");
-                    console.log("Redirecting to stored location " + 
redirectTo);
-                    sessionStorage.setItem("auth.state", "authenticated");
-                    sessionStorage.removeItem("http401");
-                    $location.path(redirectTo).hash("");
+                console.debug(`Callback. Got code: ${code} \nCalling token 
endpoint:: ${tokenEndpoint} `);
+                AuthenticationService.getOAuthTokens(tokenEndpoint, 
data).then(function(response) {

Review Comment:
   > One outstanding question is: how can we incorporate the /token URL into 
the list of allowed URLs in the CSP connect-src directive? For now, this is 
manually added in server/etc/jetty.xml.’
   
   Yea, we need backend to be able to generate CSP header dynamically (now it 
is set statically in `jetty.xml`). Let's explore that.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@solr.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@solr.apache.org
For additional commands, e-mail: issues-h...@solr.apache.org

Reply via email to