Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Root Object #165

Closed
v-ajitpanda opened this issue Nov 4, 2024 · 6 comments · Fixed by #166
Closed

Get Root Object #165

v-ajitpanda opened this issue Nov 4, 2024 · 6 comments · Fixed by #166

Comments

@v-ajitpanda
Copy link

Is it possible to use username and password to get the get root object. I am trying to connect to RM. To connect to RM we need to give username and password. So while I am creating an root object I am giving ip, username, password and default prefix also I am giving check_connectivity = False, so at that time it not calling get root object. But while loging in its checking for again get root object. Inside get root object we are not using any username and password so its giving always 401 error. Could you help me with this.

redfish_ifc = redfish.redfish_client(
"",
username="",
password="",
default_prefix="/redfish/v1",
timeout=30,
check_connectivity=False
)
redfish_ifc.login(auth="basic", username="", password="")
res = redfish_ifc.get("/redfish/v1/Systems")

This is the get root object
def get_root_object(self):
"""Perform an initial get and store the result"""
try:
resp = self.get(self.default_prefix)
except Exception as excp:
raise excp

    if resp.status != 200:
        raise ServerDownOrUnreachableError("Server not reachable, " \
                                           "return code: %d" % resp.status,response=resp)

    content = resp.text

    try:
        root_data = json.loads(content)
    except:
        str = 'Service responded with invalid JSON at URI {}\n{}'.format(
            self.default_prefix, content)
        LOGGER.error(str)
        raise JsonDecodingError(str) from None

    self.root = RisObject.parse(root_data)
    self.root_resp = resp

def login(self, username=None, password=None, auth=AuthMethod.SESSION):
"""Login and start a REST session. Remember to call logout() when"""
""" you are done.

    :param username: the user name.
    :type username: str.
    :param password: the password.
    :type password: str.
    :param auth: authentication method
    :type auth: object/instance of class AuthMethod

    """
    if getattr(self, "root_resp", None) is None:
        print("Getting root")
        self.get_root_object()

    self.__username = username if username else self.__username
    self.__password = password if password else self.__password

    if auth == AuthMethod.BASIC:
        auth_key = base64.b64encode(('%s:%s' % (self.__username,
                        self.__password)).encode('utf-8')).decode('utf-8')
        self.__authorization_key = 'Basic %s' % auth_key

        headers = dict()
        headers['Authorization'] = self.__authorization_key

        respvalidate = self._rest_request(self.login_url, headers=headers)

        if respvalidate.status == 401:
            # Invalid credentials supplied
            raise InvalidCredentialsError('HTTP 401 Unauthorized returned: Invalid credentials supplied')
    elif auth == AuthMethod.SESSION:
        data = dict()
        data['UserName'] = self.__username
        data['Password'] = self.__password

        headers = dict()
        resp = self._rest_request(self.login_url, method="POST",body=data,
                                  headers=headers, allow_redirects=False)

        LOGGER.info('Login returned code %s: %s', resp.status, resp.text)

        self.__session_key = resp.session_key
        self.__session_location = resp.session_location

        message_item = search_message(resp, "Base", "PasswordChangeRequired")
        if not message_item is None:
            raise RedfishPasswordChangeRequiredError("Password Change Required\n", message_item["MessageArgs"][0])

        if not self.__session_key and resp.status not in [200, 201, 202, 204]:
            if resp.status == 401:
                # Invalid credentials supplied
                raise InvalidCredentialsError('HTTP 401 Unauthorized returned: Invalid credentials supplied')
            else:
                # Other type of error during session creation
                error_str = resp.text
                try:
                    error_str = resp.dict["error"]["@Message.ExtendedInfo"][0]["Message"]
                except:
                    try:
                        error_str = resp.dict["error"]["message"]
                    except:
                        pass
                raise SessionCreationError('HTTP {}: Failed to created the session\n{}'.format(resp.status, error_str))
    else:
        pass
@mraineri
Copy link
Contributor

mraineri commented Nov 4, 2024

When going through the initial get_root_object flow, the intent is to check the service to see if it's alive, and cache it for future usage. It does not provide credentials at this point because this is a simple discovery of the service before we attempt to log in. The service root is expected to be available without authentication per the "Authentication requirements" of the Redfish Specification.

Unfortunately you'll need to request support from your vendor. They have a bug in their service that requires a fix.

@mraineri
Copy link
Contributor

mraineri commented Nov 4, 2024

Another user encountered the same issue on their system. They provided a workaround here: #157

@v-ajitpanda
Copy link
Author

Hi @mraineri

Thanks a lot for the response.

Can we have this optional as get root object? because I am able to login without this get root object and later I can assign the root_resp after login for future usage.

I have a temp fix for this like I can use


redfish_ifc = redfish.redfish_client(
            "",
            username="",
            password="",
            default_prefix="/redfish/v1",
            timeout=30,
            check_connectivity=False
        )
redfish_ifc.root_resp = redfish_ifc
redfish_ifc.login(auth="basic")   
print("Redfish login is successful.")
res = redfish_ifc.get("/redfish/v1")
redfish_ifc.root_resp = res.json

But If its optional like in redfish_client , then it will help a lot. Because here every URI is password protected.

Thank you

@mraineri
Copy link
Contributor

@v-ajitpanda I brought this up with others for discussion. While we're still concerned changing things would encourage non-conformant behavior, we think we have a middleground in mind to move things along for you.

What we'd like to do is in get_root_object, we can intercept a 401 response and handle it without raising an exception. We'd also like to show warnings to a user about the non-conformance to bring this to the attention of the user (like what we do in Redfish-Tacklebox here: https://github.com/DMTF/Redfish-Tacklebox/blob/main/redfish_utilities/systems.py#L675)

Would this path be okay?

@v-ajitpanda
Copy link
Author

Thanks Mike. This will unblock us while pushing for conformance, at the same time.

@v-ajitpanda
Copy link
Author

Thank you, Mike, I tried the patch, and it helps establish connection. Previously we could not establish connection because it was mandating authorization for /redfish/v1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants