Skip to content
Snippets Groups Projects
Verified Commit 408ee0a3 authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Implement PAM auth step

parent 21abd44d
No related branches found
No related tags found
No related merge requests found
......@@ -18,13 +18,15 @@ import toml
DEFAULT_CONFIG_FILE = "/etc/nss_pam_oidc.toml"
DEFAULT_CONFIG = {
"pam": {},
"pam": {
"flow": "password",
},
"nss": {},
}
def get_config(section: str, **kwargs):
"""Get configuration for a section, layered from defaults, config file, and args."""
def load_config(config_file: str) -> dict[str, dict[str, str]]:
"""Load full configuration, amended wit hdefault config."""
config = {}
# First, copy default configuration
......@@ -32,13 +34,25 @@ def get_config(section: str, **kwargs):
config[name] = conf.copy()
# Second, load configuration from file
config_file = kwargs.pop("config", DEFAULT_CONFIG_FILE)
if os.path.exists(config_file):
config_toml = toml.load(config_file)
for name, conf in config.items():
conf.update(config_toml.get(name, {}))
return config
def get_config(section: str, **kwargs) -> dict[str, str]:
"""Get configuration for a section, layered from defaults, config file, and args."""
config_file = kwargs.pop("config", DEFAULT_CONFIG_FILE)
config = load_config(config_file)
# Lastly, override with passed arguments
config[section].update(kwargs)
return config
return config[section]
def filter_config(config: dict[str, str], keys: list[str]) -> dict[str, str]:
"""Return a copy of the config dictionary with only the requested keys."""
return {k: v for k, v in config.items() if k in keys}
......@@ -12,26 +12,79 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from oauthlib.oauth2 import InvalidGrantError, LegacyApplicationClient
from requests.exceptions import RequestException
from requests_oauthlib import OAuth2Session
from .config import filter_config, get_config
def _split_argv(argv: list[str]) -> dict[str, str]:
args = {}
for arg in argv:
if "=" in arg:
name, val = arg.split("=", 1)
else:
name, val = arg, True
args[name] = val
return args
def _do_legacy_auth(username: str, password: str, config: dict[str, str]):
client_config = filter_config(config, ["client_id"])
session_config = filter_config(config, ["client_id"])
fetch_config = filter_config(config, ["client_id", "client_secret", "token_url"])
client = LegacyApplicationClient(**client_config)
session = OAuth2Session(client=client, **session_config)
token = session.fetch_token(username=username, password=password, **fetch_config)
return token
def pam_sm_authenticate(pamh, flags, argv):
try:
user = pamh.get_user(None)
except pamh.exception as e:
return e.pam_result
if user == None:
pamh.user = DEFAULT_USER
return pamh.PAM_SUCCESS
args = _split_argv(argv)
config = get_config("pam", args)
if config.pop("flow") == "password":
try:
user = pamh.get_user(None)
password = pamh.authtok
except pamh.exception as e:
return e.pam_result
if user is None or password is None:
return pamh.PAM_CRED_INSUFFICIENT
try:
token = _do_legacy_auth(username, password)
except InvalidGrantError:
return pamh.PAM_AUTH_ERROR
except RequestException:
return pamh.PAM_AUTHINFO_UNAVAIL
except:
return pamh.PAM_SERVICE_ERR
if "access_token" in token:
return pamh.PAM_SUCCESS
return pamh.PAM_AUTH_ERR
def pam_sm_setcred(pamh, flags, argv):
return pamh.PAM_SUCCESS
return pamh.PAM_SUCCESS
def pam_sm_acct_mgmt(pamh, flags, argv):
return pamh.PAM_SUCCESS
return pamh.PAM_SUCCESS
def pam_sm_open_session(pamh, flags, argv):
return pamh.PAM_SUCCESS
return pamh.PAM_SUCCESS
def pam_sm_close_session(pamh, flags, argv):
return pamh.PAM_SUCCESS
return pamh.PAM_SUCCESS
def pam_sm_chauthtok(pamh, flags, argv):
return pamh.PAM_SUCCESS
return pamh.PAM_SUCCESS
......@@ -14,6 +14,8 @@ classifiers = [
[tool.poetry.dependencies]
python = "^3.9"
toml = "^0.10.2"
oauthlib = "^3.1.0"
requests-oauthlib = "^1.3.0"
[tool.poetry.dev-dependencies]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment