DPDK CI discussions
 help / color / mirror / Atom feed
* [PATCH v1] tools: add jwt renewal function to acvp_tool
@ 2023-06-21 19:53 jspewock
  2023-06-23 14:14 ` Aaron Conole
  0 siblings, 1 reply; 5+ messages in thread
From: jspewock @ 2023-06-21 19:53 UTC (permalink / raw)
  To: aconole; +Cc: ci, Jeremy Spewock

From: Jeremy Spewock <jspewock@iol.unh.edu>

Adds a method that follows the process for renewing your jwt according
to NIST API documentation. This way, if there are load issues and it
takes too long to get vectors back with multi-algorithm testing, you can
still get restuls and the script will not error.

Also, added a maximum number of renewals so that the script cannot run
infinitely.

Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
---
 tools/acvp/acvp_tool.py | 73 +++++++++++++++++++++++++++++++++++------
 1 file changed, 63 insertions(+), 10 deletions(-)

diff --git a/tools/acvp/acvp_tool.py b/tools/acvp/acvp_tool.py
index 40d2f2f..8d50a58 100755
--- a/tools/acvp/acvp_tool.py
+++ b/tools/acvp/acvp_tool.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2022 The University of New Hampshire
+# Copyright 2023 The University of New Hampshire
 
 import hashlib
 import sys
@@ -36,6 +36,8 @@ class ACVPProxy:
         self.totp_path: str = totp_path
         self.login_data: Optional[Dict[str, Any]] = None
         self.session_data: Optional[Dict[str, Any]] = None
+        self.retries: int = 0
+        self.max_retries: int = 2
 
         with open(config_path, 'r') as f:
             self.config: Any = json.load(f)
@@ -70,7 +72,13 @@ class ACVPProxy:
                 cert=self.cert,
                 headers={'Authorization': f'Bearer {token}'}
             )
-            if not response.ok:
+            if response.status_code == 401:
+                if self.__renew_jwt():
+                    token = self.session_data['jwt']
+                    continue
+                logging.error("Failed to renew expired jwt")
+                return None
+            elif not response.ok:
                 logging.error(f'Failed to fetch vector set {url}')
                 logging.error(json.dumps(response.json(), indent=4))
                 return None
@@ -85,6 +93,35 @@ class ACVPProxy:
             logging.info(f'Downloaded vector set {url}')
             return vector_set_json
 
+    def __renew_jwt(self) -> bool:
+        """Renews the jwt in session_data.
+
+        JWTs provided by the NIST API last 30 minutes which can cause this
+        script to fail even with good data. This method renews the jwt using
+        the login endpoint.
+
+        @return: True if successfully renewed token
+        """
+        if self.retries >= self.max_retries:
+            logging.error("Maximum number of jwt renewals has been reached.")
+            return False
+        response = requests.post(
+            url=f'{self.config["url"]}/acvp/v1/login',
+            json=[
+                {'acvVersion': '1.0'},
+                {
+                'password': self.__get_totp(),
+                'accessToken': self.session_data["jwt"]
+                }
+            ],
+            cert=self.cert,
+        )
+        if response.ok:
+            self.retries += 1
+            self.session_data["jwt"] = response.json()[1].pop("accessToken")
+            return True
+        return False
+
     def login(self) -> bool:
         """Log into the API server.
 
@@ -141,7 +178,6 @@ class ACVPProxy:
             cert=self.cert,
             headers={'Authorization': f'Bearer {self.login_data["jwt"]}'}
         )
-
         if not response.ok:
             logging.error('Unable to register.')
             logging.error(json.dumps(response.json(), indent=4))
@@ -178,6 +214,12 @@ class ACVPProxy:
                         'Authorization': f'Bearer {self.session_data["jwt"]}'
                     }
                 )
+                if result.status_code == 401:
+                    if self.__renew_jwt():
+                        write_data[0]["jwt"] = self.session_data["jwt"]
+                        continue
+                    logging.error("Failed to renew jwt")
+                    return None
                 version, result_json = result.json()
                 if 'retry' in result_json:
                     duration = result_json['retry']
@@ -207,8 +249,19 @@ class ACVPProxy:
                 cert=self.cert,
                 headers={'Authorization': f'Bearer {self.session_data["jwt"]}'}
             )
-
-            if not response.ok:
+            if response.status_code == 401:
+                if self.__renew_jwt():
+                    response = requests.post(
+                        f'{self.config["url"]}{session_url}/vectorSets/'
+                        f'{vector_set["vsId"]}/results',
+                        json=[version, vector_set],
+                        cert=self.cert,
+                        headers={'Authorization': f'Bearer {self.session_data["jwt"]}'}
+                    )
+                else:
+                    logging.error("Failed to renew jwt")
+                    return False
+            elif not response.ok:
                 has_error = True
                 logging.error(f'Could not upload vector set response for '
                               f'vector set ID {vector_set["vsId"]}.')
@@ -239,13 +292,13 @@ def main(request_path: Optional[str],
         config_path=config_path,
     )
 
-    logging.info('Attempting to log in...')
-    if not proxy.login():
-        logging.error('Could not log in.')
-        sys.exit(1)
-    logging.info('Successfully logged in.')
 
     if request_path:
+        logging.info('Attempting to log in...')
+        if not proxy.login():
+            logging.error('Could not log in.')
+            sys.exit(1)
+        logging.info('Successfully logged in.')
         logging.info('Creating a new test session and downloading vectors...')
         test_session = proxy.register()
         if not test_session:
-- 
2.41.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] tools: add jwt renewal function to acvp_tool
  2023-06-21 19:53 [PATCH v1] tools: add jwt renewal function to acvp_tool jspewock
@ 2023-06-23 14:14 ` Aaron Conole
  2023-06-23 21:23   ` Jeremy Spewock
  0 siblings, 1 reply; 5+ messages in thread
From: Aaron Conole @ 2023-06-23 14:14 UTC (permalink / raw)
  To: jspewock; +Cc: ci

jspewock@iol.unh.edu writes:

> From: Jeremy Spewock <jspewock@iol.unh.edu>
>
> Adds a method that follows the process for renewing your jwt according
> to NIST API documentation. This way, if there are load issues and it
> takes too long to get vectors back with multi-algorithm testing, you can
> still get restuls and the script will not error.
>
> Also, added a maximum number of renewals so that the script cannot run
> infinitely.
>
> Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
> ---

Just some nits - I haven't run this through black / flake8.

>  tools/acvp/acvp_tool.py | 73 +++++++++++++++++++++++++++++++++++------
>  1 file changed, 63 insertions(+), 10 deletions(-)
>
> diff --git a/tools/acvp/acvp_tool.py b/tools/acvp/acvp_tool.py
> index 40d2f2f..8d50a58 100755
> --- a/tools/acvp/acvp_tool.py
> +++ b/tools/acvp/acvp_tool.py
> @@ -1,7 +1,7 @@
>  #!/usr/bin/env python3
>  
>  # SPDX-License-Identifier: BSD-3-Clause
> -# Copyright 2022 The University of New Hampshire
> +# Copyright 2023 The University of New Hampshire
>  
>  import hashlib
>  import sys
> @@ -36,6 +36,8 @@ class ACVPProxy:
>          self.totp_path: str = totp_path
>          self.login_data: Optional[Dict[str, Any]] = None
>          self.session_data: Optional[Dict[str, Any]] = None
> +        self.retries: int = 0
> +        self.max_retries: int = 2
>  
>          with open(config_path, 'r') as f:
>              self.config: Any = json.load(f)
> @@ -70,7 +72,13 @@ class ACVPProxy:
>                  cert=self.cert,
>                  headers={'Authorization': f'Bearer {token}'}
>              )
> -            if not response.ok:
> +            if response.status_code == 401:
> +                if self.__renew_jwt():
> +                    token = self.session_data['jwt']
> +                    continue
> +                logging.error("Failed to renew expired jwt")
> +                return None
> +            elif not response.ok:
>                  logging.error(f'Failed to fetch vector set {url}')
>                  logging.error(json.dumps(response.json(), indent=4))
>                  return None
> @@ -85,6 +93,35 @@ class ACVPProxy:
>              logging.info(f'Downloaded vector set {url}')
>              return vector_set_json
>  
> +    def __renew_jwt(self) -> bool:
> +        """Renews the jwt in session_data.
> +
> +        JWTs provided by the NIST API last 30 minutes which can cause this
> +        script to fail even with good data. This method renews the jwt using
> +        the login endpoint.
> +
> +        @return: True if successfully renewed token
> +        """
> +        if self.retries >= self.max_retries:
> +            logging.error("Maximum number of jwt renewals has been reached.")
> +            return False
> +        response = requests.post(
> +            url=f'{self.config["url"]}/acvp/v1/login',
> +            json=[
> +                {'acvVersion': '1.0'},
> +                {
> +                'password': self.__get_totp(),
> +                'accessToken': self.session_data["jwt"]
> +                }
> +            ],
> +            cert=self.cert,
> +        )
> +        if response.ok:
> +            self.retries += 1
> +            self.session_data["jwt"] = response.json()[1].pop("accessToken")
> +            return True
> +        return False
> +
>      def login(self) -> bool:
>          """Log into the API server.
>  
> @@ -141,7 +178,6 @@ class ACVPProxy:
>              cert=self.cert,
>              headers={'Authorization': f'Bearer {self.login_data["jwt"]}'}
>          )
> -

Why this line changed?

>          if not response.ok:
>              logging.error('Unable to register.')
>              logging.error(json.dumps(response.json(), indent=4))
> @@ -178,6 +214,12 @@ class ACVPProxy:
>                          'Authorization': f'Bearer {self.session_data["jwt"]}'
>                      }
>                  )
> +                if result.status_code == 401:
> +                    if self.__renew_jwt():
> +                        write_data[0]["jwt"] = self.session_data["jwt"]
> +                        continue
> +                    logging.error("Failed to renew jwt")
> +                    return None
>                  version, result_json = result.json()
>                  if 'retry' in result_json:
>                      duration = result_json['retry']
> @@ -207,8 +249,19 @@ class ACVPProxy:
>                  cert=self.cert,
>                  headers={'Authorization': f'Bearer {self.session_data["jwt"]}'}
>              )
> -
> -            if not response.ok:

You also dropped a line spacing here as well.

> +            if response.status_code == 401:
> +                if self.__renew_jwt():
> +                    response = requests.post(
> +                        f'{self.config["url"]}{session_url}/vectorSets/'
> +                        f'{vector_set["vsId"]}/results',
> +                        json=[version, vector_set],
> +                        cert=self.cert,
> +                        headers={'Authorization': f'Bearer {self.session_data["jwt"]}'}
> +                    )
> +                else:
> +                    logging.error("Failed to renew jwt")
> +                    return False
> +            elif not response.ok:
>                  has_error = True
>                  logging.error(f'Could not upload vector set response for '
>                                f'vector set ID {vector_set["vsId"]}.')
> @@ -239,13 +292,13 @@ def main(request_path: Optional[str],
>          config_path=config_path,
>      )
>  
> -    logging.info('Attempting to log in...')
> -    if not proxy.login():
> -        logging.error('Could not log in.')
> -        sys.exit(1)
> -    logging.info('Successfully logged in.')
>  
>      if request_path:
> +        logging.info('Attempting to log in...')
> +        if not proxy.login():
> +            logging.error('Could not log in.')
> +            sys.exit(1)
> +        logging.info('Successfully logged in.')
>          logging.info('Creating a new test session and downloading vectors...')
>          test_session = proxy.register()
>          if not test_session:


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] tools: add jwt renewal function to acvp_tool
  2023-06-23 14:14 ` Aaron Conole
@ 2023-06-23 21:23   ` Jeremy Spewock
  2023-06-26 19:00     ` Aaron Conole
  0 siblings, 1 reply; 5+ messages in thread
From: Jeremy Spewock @ 2023-06-23 21:23 UTC (permalink / raw)
  To: Aaron Conole; +Cc: ci

[-- Attachment #1: Type: text/plain, Size: 7259 bytes --]

On Fri, Jun 23, 2023 at 10:15 AM Aaron Conole <aconole@redhat.com> wrote:

> jspewock@iol.unh.edu writes:
>
> > From: Jeremy Spewock <jspewock@iol.unh.edu>
> >
> > Adds a method that follows the process for renewing your jwt according
> > to NIST API documentation. This way, if there are load issues and it
> > takes too long to get vectors back with multi-algorithm testing, you can
> > still get restuls and the script will not error.
> >
> > Also, added a maximum number of renewals so that the script cannot run
> > infinitely.
> >
> > Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
> > ---
>
> Just some nits - I haven't run this through black / flake8.
>
> >  tools/acvp/acvp_tool.py | 73 +++++++++++++++++++++++++++++++++++------
> >  1 file changed, 63 insertions(+), 10 deletions(-)
> >
> > diff --git a/tools/acvp/acvp_tool.py b/tools/acvp/acvp_tool.py
> > index 40d2f2f..8d50a58 100755
> > --- a/tools/acvp/acvp_tool.py
> > +++ b/tools/acvp/acvp_tool.py
> > @@ -1,7 +1,7 @@
> >  #!/usr/bin/env python3
> >
> >  # SPDX-License-Identifier: BSD-3-Clause
> > -# Copyright 2022 The University of New Hampshire
> > +# Copyright 2023 The University of New Hampshire
> >
> >  import hashlib
> >  import sys
> > @@ -36,6 +36,8 @@ class ACVPProxy:
> >          self.totp_path: str = totp_path
> >          self.login_data: Optional[Dict[str, Any]] = None
> >          self.session_data: Optional[Dict[str, Any]] = None
> > +        self.retries: int = 0
> > +        self.max_retries: int = 2
> >
> >          with open(config_path, 'r') as f:
> >              self.config: Any = json.load(f)
> > @@ -70,7 +72,13 @@ class ACVPProxy:
> >                  cert=self.cert,
> >                  headers={'Authorization': f'Bearer {token}'}
> >              )
> > -            if not response.ok:
> > +            if response.status_code == 401:
> > +                if self.__renew_jwt():
> > +                    token = self.session_data['jwt']
> > +                    continue
> > +                logging.error("Failed to renew expired jwt")
> > +                return None
> > +            elif not response.ok:
> >                  logging.error(f'Failed to fetch vector set {url}')
> >                  logging.error(json.dumps(response.json(), indent=4))
> >                  return None
> > @@ -85,6 +93,35 @@ class ACVPProxy:
> >              logging.info(f'Downloaded vector set {url}')
> >              return vector_set_json
> >
> > +    def __renew_jwt(self) -> bool:
> > +        """Renews the jwt in session_data.
> > +
> > +        JWTs provided by the NIST API last 30 minutes which can cause
> this
> > +        script to fail even with good data. This method renews the jwt
> using
> > +        the login endpoint.
> > +
> > +        @return: True if successfully renewed token
> > +        """
> > +        if self.retries >= self.max_retries:
> > +            logging.error("Maximum number of jwt renewals has been
> reached.")
> > +            return False
> > +        response = requests.post(
> > +            url=f'{self.config["url"]}/acvp/v1/login',
> > +            json=[
> > +                {'acvVersion': '1.0'},
> > +                {
> > +                'password': self.__get_totp(),
> > +                'accessToken': self.session_data["jwt"]
> > +                }
> > +            ],
> > +            cert=self.cert,
> > +        )
> > +        if response.ok:
> > +            self.retries += 1
> > +            self.session_data["jwt"] =
> response.json()[1].pop("accessToken")
> > +            return True
> > +        return False
> > +
> >      def login(self) -> bool:
> >          """Log into the API server.
> >
> > @@ -141,7 +178,6 @@ class ACVPProxy:
> >              cert=self.cert,
> >              headers={'Authorization': f'Bearer
> {self.login_data["jwt"]}'}
> >          )
> > -
>
> Why this line changed?
>

I guess this line just ended up getting removed when I was making edits. I
didn't do it for any deliberate reason other than spacing when I was making
edits.


>
> >          if not response.ok:
> >              logging.error('Unable to register.')
> >              logging.error(json.dumps(response.json(), indent=4))
> > @@ -178,6 +214,12 @@ class ACVPProxy:
> >                          'Authorization': f'Bearer
> {self.session_data["jwt"]}'
> >                      }
> >                  )
> > +                if result.status_code == 401:
> > +                    if self.__renew_jwt():
> > +                        write_data[0]["jwt"] = self.session_data["jwt"]
> > +                        continue
> > +                    logging.error("Failed to renew jwt")
> > +                    return None
> >                  version, result_json = result.json()
> >                  if 'retry' in result_json:
> >                      duration = result_json['retry']
> > @@ -207,8 +249,19 @@ class ACVPProxy:
> >                  cert=self.cert,
> >                  headers={'Authorization': f'Bearer
> {self.session_data["jwt"]}'}
> >              )
> > -
> > -            if not response.ok:
>
> You also dropped a line spacing here as well.
>

I think this is the same thing as above, when I was testing and writing
things in a couple of places this line also disappeared just because I felt
it wasn't needed, but there wasn't any particular reason.


>
> > +            if response.status_code == 401:
> > +                if self.__renew_jwt():
> > +                    response = requests.post(
> > +                        f'{self.config["url"]}{session_url}/vectorSets/'
> > +                        f'{vector_set["vsId"]}/results',
> > +                        json=[version, vector_set],
> > +                        cert=self.cert,
> > +                        headers={'Authorization': f'Bearer
> {self.session_data["jwt"]}'}
> > +                    )
> > +                else:
> > +                    logging.error("Failed to renew jwt")
> > +                    return False
> > +            elif not response.ok:
> >                  has_error = True
> >                  logging.error(f'Could not upload vector set response
> for '
> >                                f'vector set ID {vector_set["vsId"]}.')
> > @@ -239,13 +292,13 @@ def main(request_path: Optional[str],
> >          config_path=config_path,
> >      )
> >
> > -    logging.info('Attempting to log in...')
> > -    if not proxy.login():
> > -        logging.error('Could not log in.')
> > -        sys.exit(1)
> > -    logging.info('Successfully logged in.')
> >
> >      if request_path:
> > +        logging.info('Attempting to log in...')
> > +        if not proxy.login():
> > +            logging.error('Could not log in.')
> > +            sys.exit(1)
> > +        logging.info('Successfully logged in.')
> >          logging.info('Creating a new test session and downloading
> vectors...')
> >          test_session = proxy.register()
> >          if not test_session:
>

Would it be preferred that I add these lines back so that they closer align
with the original script?

Thanks,
Jeremy

[-- Attachment #2: Type: text/html, Size: 11109 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] tools: add jwt renewal function to acvp_tool
  2023-06-23 21:23   ` Jeremy Spewock
@ 2023-06-26 19:00     ` Aaron Conole
  2023-06-26 21:38       ` Jeremy Spewock
  0 siblings, 1 reply; 5+ messages in thread
From: Aaron Conole @ 2023-06-26 19:00 UTC (permalink / raw)
  To: Jeremy Spewock; +Cc: ci

Jeremy Spewock <jspewock@iol.unh.edu> writes:

> On Fri, Jun 23, 2023 at 10:15 AM Aaron Conole <aconole@redhat.com> wrote:
>
>  jspewock@iol.unh.edu writes:
>
>  > From: Jeremy Spewock <jspewock@iol.unh.edu>
>  >
>  > Adds a method that follows the process for renewing your jwt according
>  > to NIST API documentation. This way, if there are load issues and it
>  > takes too long to get vectors back with multi-algorithm testing, you can
>  > still get restuls and the script will not error.
>  >
>  > Also, added a maximum number of renewals so that the script cannot run
>  > infinitely.
>  >
>  > Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
>  > ---
>
>  Just some nits - I haven't run this through black / flake8.
>
>  >  tools/acvp/acvp_tool.py | 73 +++++++++++++++++++++++++++++++++++------
>  >  1 file changed, 63 insertions(+), 10 deletions(-)
>  >
>  > diff --git a/tools/acvp/acvp_tool.py b/tools/acvp/acvp_tool.py
>  > index 40d2f2f..8d50a58 100755
>  > --- a/tools/acvp/acvp_tool.py
>  > +++ b/tools/acvp/acvp_tool.py
>  > @@ -1,7 +1,7 @@
>  >  #!/usr/bin/env python3
>  >  
>  >  # SPDX-License-Identifier: BSD-3-Clause
>  > -# Copyright 2022 The University of New Hampshire
>  > +# Copyright 2023 The University of New Hampshire
>  >  
>  >  import hashlib
>  >  import sys
>  > @@ -36,6 +36,8 @@ class ACVPProxy:
>  >          self.totp_path: str = totp_path
>  >          self.login_data: Optional[Dict[str, Any]] = None
>  >          self.session_data: Optional[Dict[str, Any]] = None
>  > +        self.retries: int = 0
>  > +        self.max_retries: int = 2
>  >  
>  >          with open(config_path, 'r') as f:
>  >              self.config: Any = json.load(f)
>  > @@ -70,7 +72,13 @@ class ACVPProxy:
>  >                  cert=self.cert,
>  >                  headers={'Authorization': f'Bearer {token}'}
>  >              )
>  > -            if not response.ok:
>  > +            if response.status_code == 401:
>  > +                if self.__renew_jwt():
>  > +                    token = self.session_data['jwt']
>  > +                    continue
>  > +                logging.error("Failed to renew expired jwt")
>  > +                return None
>  > +            elif not response.ok:
>  >                  logging.error(f'Failed to fetch vector set {url}')
>  >                  logging.error(json.dumps(response.json(), indent=4))
>  >                  return None
>  > @@ -85,6 +93,35 @@ class ACVPProxy:
>  >              logging.info(f'Downloaded vector set {url}')
>  >              return vector_set_json
>  >  
>  > +    def __renew_jwt(self) -> bool:
>  > +        """Renews the jwt in session_data.
>  > +
>  > +        JWTs provided by the NIST API last 30 minutes which can cause this
>  > +        script to fail even with good data. This method renews the jwt using
>  > +        the login endpoint.
>  > +
>  > +        @return: True if successfully renewed token
>  > +        """
>  > +        if self.retries >= self.max_retries:
>  > +            logging.error("Maximum number of jwt renewals has been reached.")
>  > +            return False
>  > +        response = requests.post(
>  > +            url=f'{self.config["url"]}/acvp/v1/login',
>  > +            json=[
>  > +                {'acvVersion': '1.0'},
>  > +                {
>  > +                'password': self.__get_totp(),
>  > +                'accessToken': self.session_data["jwt"]
>  > +                }
>  > +            ],
>  > +            cert=self.cert,
>  > +        )
>  > +        if response.ok:
>  > +            self.retries += 1
>  > +            self.session_data["jwt"] = response.json()[1].pop("accessToken")
>  > +            return True
>  > +        return False
>  > +
>  >      def login(self) -> bool:
>  >          """Log into the API server.
>  >  
>  > @@ -141,7 +178,6 @@ class ACVPProxy:
>  >              cert=self.cert,
>  >              headers={'Authorization': f'Bearer {self.login_data["jwt"]}'}
>  >          )
>  > -
>
>  Why this line changed?
>
> I guess this line just ended up getting removed when I was making edits. I didn't do it for any deliberate
> reason other than spacing when I was making edits.
>  
>  
>  >          if not response.ok:
>  >              logging.error('Unable to register.')
>  >              logging.error(json.dumps(response.json(), indent=4))
>  > @@ -178,6 +214,12 @@ class ACVPProxy:
>  >                          'Authorization': f'Bearer {self.session_data["jwt"]}'
>  >                      }
>  >                  )
>  > +                if result.status_code == 401:
>  > +                    if self.__renew_jwt():
>  > +                        write_data[0]["jwt"] = self.session_data["jwt"]
>  > +                        continue
>  > +                    logging.error("Failed to renew jwt")
>  > +                    return None
>  >                  version, result_json = result.json()
>  >                  if 'retry' in result_json:
>  >                      duration = result_json['retry']
>  > @@ -207,8 +249,19 @@ class ACVPProxy:
>  >                  cert=self.cert,
>  >                  headers={'Authorization': f'Bearer {self.session_data["jwt"]}'}
>  >              )
>  > -
>  > -            if not response.ok:
>
>  You also dropped a line spacing here as well.
>
> I think this is the same thing as above, when I was testing and writing things in a couple of places this line
> also disappeared just because I felt it wasn't needed, but there wasn't any particular reason.
>  
>  
>  > +            if response.status_code == 401:
>  > +                if self.__renew_jwt():
>  > +                    response = requests.post(
>  > +                        f'{self.config["url"]}{session_url}/vectorSets/'
>  > +                        f'{vector_set["vsId"]}/results',
>  > +                        json=[version, vector_set],
>  > +                        cert=self.cert,
>  > +                        headers={'Authorization': f'Bearer {self.session_data["jwt"]}'}
>  > +                    )
>  > +                else:
>  > +                    logging.error("Failed to renew jwt")
>  > +                    return False
>  > +            elif not response.ok:
>  >                  has_error = True
>  >                  logging.error(f'Could not upload vector set response for '
>  >                                f'vector set ID {vector_set["vsId"]}.')
>  > @@ -239,13 +292,13 @@ def main(request_path: Optional[str],
>  >          config_path=config_path,
>  >      )
>  >  
>  > -    logging.info('Attempting to log in...')
>  > -    if not proxy.login():
>  > -        logging.error('Could not log in.')
>  > -        sys.exit(1)
>  > -    logging.info('Successfully logged in.')
>  >  
>  >      if request_path:
>  > +        logging.info('Attempting to log in...')
>  > +        if not proxy.login():
>  > +            logging.error('Could not log in.')
>  > +            sys.exit(1)
>  > +        logging.info('Successfully logged in.')
>  >          logging.info('Creating a new test session and downloading vectors...')
>  >          test_session = proxy.register()
>  >          if not test_session:
>
> Would it be preferred that I add these lines back so that they closer align with the original script?

Please do, yes.  Try to keep whitespace changes to a minimum.  It gets
to be difficult sometimes to review.

> Thanks,
> Jeremy


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] tools: add jwt renewal function to acvp_tool
  2023-06-26 19:00     ` Aaron Conole
@ 2023-06-26 21:38       ` Jeremy Spewock
  0 siblings, 0 replies; 5+ messages in thread
From: Jeremy Spewock @ 2023-06-26 21:38 UTC (permalink / raw)
  To: Aaron Conole; +Cc: ci

[-- Attachment #1: Type: text/plain, Size: 8079 bytes --]

Fixed in v2, thanks for the feedback!

-Jeremy

On Mon, Jun 26, 2023 at 3:00 PM Aaron Conole <aconole@redhat.com> wrote:

> Jeremy Spewock <jspewock@iol.unh.edu> writes:
>
> > On Fri, Jun 23, 2023 at 10:15 AM Aaron Conole <aconole@redhat.com>
> wrote:
> >
> >  jspewock@iol.unh.edu writes:
> >
> >  > From: Jeremy Spewock <jspewock@iol.unh.edu>
> >  >
> >  > Adds a method that follows the process for renewing your jwt according
> >  > to NIST API documentation. This way, if there are load issues and it
> >  > takes too long to get vectors back with multi-algorithm testing, you
> can
> >  > still get restuls and the script will not error.
> >  >
> >  > Also, added a maximum number of renewals so that the script cannot run
> >  > infinitely.
> >  >
> >  > Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
> >  > ---
> >
> >  Just some nits - I haven't run this through black / flake8.
> >
> >  >  tools/acvp/acvp_tool.py | 73
> +++++++++++++++++++++++++++++++++++------
> >  >  1 file changed, 63 insertions(+), 10 deletions(-)
> >  >
> >  > diff --git a/tools/acvp/acvp_tool.py b/tools/acvp/acvp_tool.py
> >  > index 40d2f2f..8d50a58 100755
> >  > --- a/tools/acvp/acvp_tool.py
> >  > +++ b/tools/acvp/acvp_tool.py
> >  > @@ -1,7 +1,7 @@
> >  >  #!/usr/bin/env python3
> >  >
> >  >  # SPDX-License-Identifier: BSD-3-Clause
> >  > -# Copyright 2022 The University of New Hampshire
> >  > +# Copyright 2023 The University of New Hampshire
> >  >
> >  >  import hashlib
> >  >  import sys
> >  > @@ -36,6 +36,8 @@ class ACVPProxy:
> >  >          self.totp_path: str = totp_path
> >  >          self.login_data: Optional[Dict[str, Any]] = None
> >  >          self.session_data: Optional[Dict[str, Any]] = None
> >  > +        self.retries: int = 0
> >  > +        self.max_retries: int = 2
> >  >
> >  >          with open(config_path, 'r') as f:
> >  >              self.config: Any = json.load(f)
> >  > @@ -70,7 +72,13 @@ class ACVPProxy:
> >  >                  cert=self.cert,
> >  >                  headers={'Authorization': f'Bearer {token}'}
> >  >              )
> >  > -            if not response.ok:
> >  > +            if response.status_code == 401:
> >  > +                if self.__renew_jwt():
> >  > +                    token = self.session_data['jwt']
> >  > +                    continue
> >  > +                logging.error("Failed to renew expired jwt")
> >  > +                return None
> >  > +            elif not response.ok:
> >  >                  logging.error(f'Failed to fetch vector set {url}')
> >  >                  logging.error(json.dumps(response.json(), indent=4))
> >  >                  return None
> >  > @@ -85,6 +93,35 @@ class ACVPProxy:
> >  >              logging.info(f'Downloaded vector set {url}')
> >  >              return vector_set_json
> >  >
> >  > +    def __renew_jwt(self) -> bool:
> >  > +        """Renews the jwt in session_data.
> >  > +
> >  > +        JWTs provided by the NIST API last 30 minutes which can
> cause this
> >  > +        script to fail even with good data. This method renews the
> jwt using
> >  > +        the login endpoint.
> >  > +
> >  > +        @return: True if successfully renewed token
> >  > +        """
> >  > +        if self.retries >= self.max_retries:
> >  > +            logging.error("Maximum number of jwt renewals has been
> reached.")
> >  > +            return False
> >  > +        response = requests.post(
> >  > +            url=f'{self.config["url"]}/acvp/v1/login',
> >  > +            json=[
> >  > +                {'acvVersion': '1.0'},
> >  > +                {
> >  > +                'password': self.__get_totp(),
> >  > +                'accessToken': self.session_data["jwt"]
> >  > +                }
> >  > +            ],
> >  > +            cert=self.cert,
> >  > +        )
> >  > +        if response.ok:
> >  > +            self.retries += 1
> >  > +            self.session_data["jwt"] =
> response.json()[1].pop("accessToken")
> >  > +            return True
> >  > +        return False
> >  > +
> >  >      def login(self) -> bool:
> >  >          """Log into the API server.
> >  >
> >  > @@ -141,7 +178,6 @@ class ACVPProxy:
> >  >              cert=self.cert,
> >  >              headers={'Authorization': f'Bearer
> {self.login_data["jwt"]}'}
> >  >          )
> >  > -
> >
> >  Why this line changed?
> >
> > I guess this line just ended up getting removed when I was making edits.
> I didn't do it for any deliberate
> > reason other than spacing when I was making edits.
> >
> >
> >  >          if not response.ok:
> >  >              logging.error('Unable to register.')
> >  >              logging.error(json.dumps(response.json(), indent=4))
> >  > @@ -178,6 +214,12 @@ class ACVPProxy:
> >  >                          'Authorization': f'Bearer
> {self.session_data["jwt"]}'
> >  >                      }
> >  >                  )
> >  > +                if result.status_code == 401:
> >  > +                    if self.__renew_jwt():
> >  > +                        write_data[0]["jwt"] =
> self.session_data["jwt"]
> >  > +                        continue
> >  > +                    logging.error("Failed to renew jwt")
> >  > +                    return None
> >  >                  version, result_json = result.json()
> >  >                  if 'retry' in result_json:
> >  >                      duration = result_json['retry']
> >  > @@ -207,8 +249,19 @@ class ACVPProxy:
> >  >                  cert=self.cert,
> >  >                  headers={'Authorization': f'Bearer
> {self.session_data["jwt"]}'}
> >  >              )
> >  > -
> >  > -            if not response.ok:
> >
> >  You also dropped a line spacing here as well.
> >
> > I think this is the same thing as above, when I was testing and writing
> things in a couple of places this line
> > also disappeared just because I felt it wasn't needed, but there wasn't
> any particular reason.
> >
> >
> >  > +            if response.status_code == 401:
> >  > +                if self.__renew_jwt():
> >  > +                    response = requests.post(
> >  > +
> f'{self.config["url"]}{session_url}/vectorSets/'
> >  > +                        f'{vector_set["vsId"]}/results',
> >  > +                        json=[version, vector_set],
> >  > +                        cert=self.cert,
> >  > +                        headers={'Authorization': f'Bearer
> {self.session_data["jwt"]}'}
> >  > +                    )
> >  > +                else:
> >  > +                    logging.error("Failed to renew jwt")
> >  > +                    return False
> >  > +            elif not response.ok:
> >  >                  has_error = True
> >  >                  logging.error(f'Could not upload vector set response
> for '
> >  >                                f'vector set ID {vector_set["vsId"]}.')
> >  > @@ -239,13 +292,13 @@ def main(request_path: Optional[str],
> >  >          config_path=config_path,
> >  >      )
> >  >
> >  > -    logging.info('Attempting to log in...')
> >  > -    if not proxy.login():
> >  > -        logging.error('Could not log in.')
> >  > -        sys.exit(1)
> >  > -    logging.info('Successfully logged in.')
> >  >
> >  >      if request_path:
> >  > +        logging.info('Attempting to log in...')
> >  > +        if not proxy.login():
> >  > +            logging.error('Could not log in.')
> >  > +            sys.exit(1)
> >  > +        logging.info('Successfully logged in.')
> >  >          logging.info('Creating a new test session and downloading
> vectors...')
> >  >          test_session = proxy.register()
> >  >          if not test_session:
> >
> > Would it be preferred that I add these lines back so that they closer
> align with the original script?
>
> Please do, yes.  Try to keep whitespace changes to a minimum.  It gets
> to be difficult sometimes to review.
>
> > Thanks,
> > Jeremy
>
>

[-- Attachment #2: Type: text/html, Size: 12152 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-06-26 21:38 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-21 19:53 [PATCH v1] tools: add jwt renewal function to acvp_tool jspewock
2023-06-23 14:14 ` Aaron Conole
2023-06-23 21:23   ` Jeremy Spewock
2023-06-26 19:00     ` Aaron Conole
2023-06-26 21:38       ` Jeremy Spewock

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).