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

Fix ldap lib #54

Merged
merged 6 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ jobs:
with:
provider: microk8s
channel: 1.28-strict/stable
juju-channel: 3.2
bootstrap-options: '--agent-version=3.2.0'
juju-channel: 3.4
bootstrap-options: '--agent-version=3.4.0'

- name: Run integration tests
run: tox -e integration -- --model testing
Expand All @@ -47,7 +47,7 @@ jobs:
if: failure()

- name: Get juju logs
run: juju debug-log --replay --include unit-glauth-k8s-0
run: juju debug-log --replay --include glauth-k8s
if: failure()

- name: Get GLAuth container logs
Expand Down
61 changes: 42 additions & 19 deletions lib/charms/glauth_k8s/v0/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ def _on_ldap_requested(self, event: LdapRequestedEvent) -> None:
from pydantic import (
BaseModel,
ConfigDict,
Field,
StrictBool,
ValidationError,
field_serializer,
Expand All @@ -153,7 +154,7 @@ def _on_ldap_requested(self, event: LdapRequestedEvent) -> None:

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 3
LIBPATCH = 4

PYDEPS = ["pydantic~=2.5.3"]

Expand Down Expand Up @@ -208,6 +209,16 @@ def load(

return Secret(secret)

@classmethod
def create_or_update(cls, charm: CharmBase, label: str, content: dict[str, str]) -> "Secret":
try:
secret = charm.model.get_secret(label=label)
secret.set_content(content=content)
except SecretNotFoundError:
secret = charm.app.add_secret(label=label, content=content)

return Secret(secret)

def grant(self, relation: Relation) -> None:
self._secret.grant(relation)

Expand All @@ -216,11 +227,9 @@ def remove(self) -> None:


class LdapProviderBaseData(BaseModel):
model_config = ConfigDict(frozen=True)

url: str
base_dn: str
starttls: StrictBool
url: str = Field(frozen=True)
base_dn: str = Field(frozen=True)
starttls: StrictBool = Field(frozen=True)

@field_validator("url")
@classmethod
Expand All @@ -244,9 +253,10 @@ def serialize_bool(self, starttls: bool) -> str:


class LdapProviderData(LdapProviderBaseData):
bind_dn: str
bind_password_secret: str
auth_method: Literal["simple"]
bind_dn: str = Field(frozen=True)
bind_password: str = Field(exclude=True)
bind_password_secret: Optional[str] = None
auth_method: Literal["simple"] = Field(frozen=True)


class LdapRequirerData(BaseModel):
Expand Down Expand Up @@ -320,28 +330,38 @@ def _on_relation_broken(self, event: RelationBrokenEvent) -> None:
)
secret.remove()

def get_bind_password(self, relation_id: int) -> Optional[str]:
"""Retrieve the bind account password for a given integration."""
try:
secret = self.charm.model.get_secret(
label=BIND_ACCOUNT_SECRET_LABEL_TEMPLATE.substitute(relation_id=relation_id)
)
except SecretNotFoundError:
return None
return secret.get_content().get("password")

def update_relations_app_data(
self, /, data: Optional[LdapProviderBaseData] = None, relation_id: Optional[int] = None
self,
data: Union[LdapProviderBaseData, LdapProviderData],
/,
relation_id: Optional[int] = None,
) -> None:
"""An API for the provider charm to provide the LDAP related information."""
if data is None:
return

if not (relations := self.charm.model.relations.get(self._relation_name)):
return

if relation_id is not None:
if relation_id is not None and isinstance(data, LdapProviderData):
relations = [relation for relation in relations if relation.id == relation_id]
secret = Secret.load(
secret = Secret.create_or_update(
self.charm,
BIND_ACCOUNT_SECRET_LABEL_TEMPLATE.substitute(relation_id=relation_id),
content={"password": data.bind_password_secret},
{"password": data.bind_password},
)
secret.grant(relations[0])
data = data.model_copy(update={"bind_password_secret": secret.uri})
data.bind_password_secret = secret.uri

for relation in relations:
_update_relation_app_databag(self.charm, relation, data.model_dump()) # type: ignore[union-attr]
_update_relation_app_databag(self.charm, relation, data.model_dump())


class LdapRequirer(Object):
Expand Down Expand Up @@ -407,5 +427,8 @@ def consume_ldap_relation_data(
if not relation:
return None

provider_data = relation.data.get(relation.app)
provider_data = dict(relation.data.get(relation.app))
if secret_id := provider_data.get("bind_password_secret"):
secret = self.charm.model.get_secret(id=secret_id)
provider_data["bind_password"] = secret.get_content().get("password")
return LdapProviderData(**provider_data) if provider_data else None
Loading