Skip to content

Commit

Permalink
Merge pull request #54 from canonical/IAM-989
Browse files Browse the repository at this point in the history
Fix ldap lib
  • Loading branch information
nsklikas authored Aug 13, 2024
2 parents 8f0725b + f5a4797 commit abb1401
Show file tree
Hide file tree
Showing 10 changed files with 621 additions and 305 deletions.
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

0 comments on commit abb1401

Please sign in to comment.