Skip to content

Commit

Permalink
Merge pull request #1563 from CarlosNihelton/ad-ping-deeng-586
Browse files Browse the repository at this point in the history
Active Directory API Part 3 - Pinging the Domain Controller
  • Loading branch information
CarlosNihelton authored Feb 17, 2023
2 parents 9ed734b + b1f29c8 commit 4266a5e
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
1 change: 1 addition & 0 deletions subiquity/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ class AdDomainNameValidation(enum.Enum):
START_HYPHEN = 'Starts with a hyphen'
END_HYPHEN = 'Ends with a hyphen'
MULTIPLE_DOTS = 'Contains multiple dots'
REALM_NOT_FOUND = 'Could not find the domain controller'


class AdPasswordValidation(enum.Enum):
Expand Down
50 changes: 50 additions & 0 deletions subiquity/server/controllers/ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import logging
import re
from typing import List, Optional, Set
from subiquitycore.utils import arun_command

from subiquity.common.apidef import API
from subiquity.common.types import (
Expand All @@ -37,12 +38,45 @@
FIELD = "Domain Controller name"


class DcPingStrategy:
# Consider staging in the snap for future proof.
cmd = "/usr/sbin/realm"
arg = "discover"

async def ping(self, address: str) -> AdDomainNameValidation:
cp = await arun_command([self.cmd, self.arg, address], env={})
if cp.returncode:
return AdDomainNameValidation.REALM_NOT_FOUND

return AdDomainNameValidation.OK


class StubDcPingStrategy(DcPingStrategy):
""" For testing purpose. This class doesn't talk to the network.
Instead its response follows the following rule:
- addresses starting with "r" return REALM_NOT_FOUND;
- addresses starting with any other letter return OK. """
async def ping(self, address: str) -> AdDomainNameValidation:
if address[0] == 'r':
return AdDomainNameValidation.REALM_NOT_FOUND

return AdDomainNameValidation.OK


class ADController(SubiquityController):
""" Implements the server part of the Active Directory feature. """
model_name = "ad"
endpoint = API.active_directory
# No auto install key and schema for now due password handling uncertainty.

def __init__(self, app):
super().__init__(app)
if self.app.opts.dry_run:
self.ping_strgy = StubDcPingStrategy()
else:
self.ping_strgy = DcPingStrategy()

async def GET(self) -> Optional[ADConnectionInfo]:
"""Returns the currently configured AD settings"""
return self.model.conn_info
Expand All @@ -60,6 +94,11 @@ async def check_admin_name_GET(self, admin_name: str) \
async def check_domain_name_GET(self, domain_name: str) \
-> List[AdDomainNameValidation]:
result = AdValidators.domain_name(domain_name)
if AdDomainNameValidation.OK in result:
ping = await AdValidators.ping_domain_controller(domain_name,
self.ping_strgy)
return [ping]

return list(result)

async def check_password_GET(self, password: str) -> AdPasswordValidation:
Expand Down Expand Up @@ -154,3 +193,14 @@ def domain_name(name: str) -> Set[AdDomainNameValidation]:
return result

return {AdDomainNameValidation.OK}

@staticmethod
async def ping_domain_controller(name: str, strategy: DcPingStrategy) \
-> AdDomainNameValidation:
""" Attempts to find the specified DC in the network.
Returns either OK, EMPTY or REALM_NOT_FOUND. """

if not name:
return AdDomainNameValidation.EMPTY

return await strategy.ping(name)
5 changes: 5 additions & 0 deletions subiquity/tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1682,6 +1682,11 @@ async def test_ad(self):

self.assertIn('MULTIPLE_DOTS', result)

# Leverages the stub ping strategy
result = await instance.get(endpoint + '/check_domain_name',
data='rockbuntu.com')
self.assertIn('REALM_NOT_FOUND', result)

# Rejects invalid usernames.
result = await instance.get(endpoint + '/check_admin_name',
data='ubuntu;pro')
Expand Down

0 comments on commit 4266a5e

Please sign in to comment.