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

Bugfix: get correct principal name when keytab is given #97

Merged
merged 6 commits into from
Dec 19, 2019

Conversation

belldandyxtq
Copy link
Member

This commit fixes a bug where the principal name is not obtained
correctly when a keytab is given though KRB5_KTNAME

This closes #93
This should be tested after #96

@belldandyxtq belldandyxtq added the cat:bug Bug report or fix. label Dec 11, 2019
@belldandyxtq belldandyxtq changed the title [WIP] Bugfix: get correct principal name when keytab is given Bugfix: get correct principal name when keytab is given Dec 12, 2019
Copy link
Member

@kuenishi kuenishi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently username is only taken from keytab. But I think it can be improved more: my suggestion of taking username from krb5 info is like following::

  1. try to take username from just klist, regarding KRB5CCNAME
  2. If 1 fails, try to take it from klist -k, regarding KRB5_KTNAME
  3. If 2 fails, fall back to Unix user name.

Limitation on procedure 2 that it only takes first KVNO in the keytab must be documented precisely.

else:
os.environ['KRB5_KTNAME'] = original_krb5_ktname

chainerio.remove(keytab_path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use tempfile.TemporaryDirectory() with it's cleanup capability on with statement in case of unexpected test failure.


# save the original KRB5_KTNAME
if "KRB5_KTNAME" in os.environ:
original_krb5_ktname = os.environ['KRB5_KTNAME']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use os.getenv() or os.environ.get() for default value.


# put KRB5_KTNAME back
if original_krb5_ktname is None:
del os.environ['KRB5_KTNAME']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this must be done in finally clause in case of unexpected exceptions.

out, err = pipe.communicate()
return keytab_path

def test_get_principel_name_from_keytab(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method name indicates it being intended for unittest of def _parse_klist_keytab_output(output): somehow. Also practical unittest on parsing the output of klist had better be separated from integrated test of create_handler().

@belldandyxtq
Copy link
Member Author

The username is not only taken from keytab. If the keytab is given then we get username from keytab, otherwise from klist. If both failed, from login name.

@kuenishi
Copy link
Member

The username is not only taken from keytab. If the keytab is given then we get username from keytab, otherwise from klist. If both failed, from login name.

Yes. But the priority behaviour is different than mine. Current behaviour is 1) if KRB5_KTNAME is defined then run kinit -k and take name from keytab. 2) otherwise just run klist implicitly taking KRB5CCNAME and take name from credential file. This is different from KrbTicket behaviour and I'm worrying about potential bug that hides behind this gap. Also, with my suggestion the code would be much simpler:

  1. try taking name form klist
  2. if it failed with exception then run klist -k
  3. if it failed with exception then take the name from Unix username.

keytab_path = self.create_dummy_keytab(tmpd, dummy_username)

os.environ['KRB5_KTNAME'] = keytab_path
with HdfsFileSystem() as handler:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was not to change from create_handler to direct object construction, but to clarify what unit feature to be tested with the test method name matching test target. Hereby there're several unit functionalities here, 1) calling the klist command, 2) parsing klist command output, 3) identifying the user name. Strictly speaking, all these three must be tested one by one in unit tests. I don't request strict tests, but at least it must be clarified what is being tested here.

In other word, _parse_klist_output() is tested at (new) line 93 below, but why not _parse_klist_keytab_output(out) ? Also integrated test of those would be nice if it's done here.

This commit fixes a bug where the principal name is not obtained
correctly when a keytab is given though KRB5_KTNAME
Copy link
Member

@kuenishi kuenishi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added several nit comments. I also hope for careful documentation about this behaviour somewhere.

@@ -44,21 +49,97 @@ def test_read_non_exist(self):
with chainerio.create_handler(self.fs) as handler:
self.assertRaises(IOError, handler.open, non_exist_file)

def test_klist_not_exist(self):
path = os.environ['PATH']
def create_dummy_keytab(self, tmpd, dummy_username):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As self isn't used in this method, it should be moved out of the class.

return _parse_principal_name_from_klist(output.decode('utf-8'))


def _run_klist(keytab_path=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think passing boolean indicating -k rather than string would remove potential bug that may stem from string variations.



def _get_principal_name_from_keytab():
keytab_path = os.getenv("KRB5_KTNAME")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't this line is needed, but just running klist -k is enough. Because not only it automatically refers to KRB5_KTNAMEbut follows default fallback to /etc/krb5.keytab .


if principal_name is not None:
return principal_name
else:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else indent is not needed, I would prefer it removed for readability.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping?

@kuenishi kuenishi merged commit 14e51bd into master Dec 19, 2019
@kuenishi kuenishi deleted the bugfix_krb_keytab branch December 19, 2019 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cat:bug Bug report or fix.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bugs in getting HDFS Principal Name when keytab is given
2 participants