Create_SecureMFA_OTP_AD_attributes.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#THIS ONLY REQUIRES IF YOU PLAN TO RUN SecureMFA OTP Provider in AD MODE.
#You need to execute this script on Read-Write domain controller with AD account which is member of Schema Admins group.
#SecureMFA OTP provider when operates in AD mode ("auth_mode": "AD") it requires custom Active Directory (AD) attributes to be created to store OTP data for the user.
#This action cannot be undone and needs to be tested in your TEST domain first before moving into PRODUCTION.
#New AD Schema Attributes will be added into custom SecureMFA Auxiliary Class and that Class will be added into Existing User Class as AD Schema best practices suggest.
#OID numbers for custom attributes are from SecureMFA Private Enterprise range assigned by iana.org . Which do not overlap with other vendors OIDs numbers used to create custom AD attributes.

function ADDADSchemaAttributetoClass($SchemaAttribute)
{
    [bool]$reset = $true
    $attempts=30    
    $sleepInSeconds=180
    do
    {
        try
        {
            $reset = $true
            Write-Host "Adding $SchemaAttribute into SecureMFA Auxiliary Class.($attempts)" -ForegroundColor Green

            #Get AD Schema details
            $dse =  Get-ADRootDSE
            $schemaPath = $dse.schemaNamingContext       
            $type = 'attributeSchema'  

            #ADD AD Schema Attribute To SecureMFA Class
            $Schema = Get-ADObject -SearchBase $schemaPath -Filter "name -eq `'SecureMFA`'"
            $Schema | Set-ADObject -Add @{mayContain = $SchemaAttribute}  -ErrorAction stop             
        }
        catch [Exception]
        {
            Write-Host "Waiting for AD schema attribute refresh ... Please note this action can take a few minutes to complete." -ForegroundColor Yellow
            $reset = $false
        }            
        $attempts--

        if ($attempts -gt 0 -and $reset -eq $false) { sleep $sleepInSeconds } 
    } until ($attempts -le 0 -or $reset -eq $true)
    
    return $reset    
}

function ADDADAttribute{
 
    Param( 
        [parameter(Mandatory)]
        [String]$Name,
        [Parameter(Mandatory)]
        [String]$Description,
        [parameter(Mandatory)]
        [String]$AttributeID,
        [Parameter(Mandatory)]
        [ValidateSet('String','Int','Time','Boolean')]
        [String]$AttributeType,
        [Parameter()]
        [Boolean]$IsSingleValued = $True 
        )
 
    #Attribute values by type https://technet.microsoft.com/en-us/library/cc961740.aspx
    switch ($AttributeType) {
                'String'            {$attributeSyntax = '2.5.5.4';  $omSyntax = 20}
                'Int'               {$attributeSyntax = '2.5.5.9';  $omSyntax = 2}
                'Time'              {$attributeSyntax = '2.5.5.11'; $omSyntax = 24}
                'Boolean'           {$attributeSyntax = '2.5.5.8';  $omSyntax = 1}
                Default {}
            }    
    
    #AD atribute params-------
    $attributes = @{
    lDAPDisplayName = $Name;
    attributeId = $AttributeID;
    oMSyntax = $omSyntax;
    attributeSyntax = $attributeSyntax;
    isSingleValued = $IsSingleValued;
    adminDescription = $Description;
    searchflags = 0
            }
    #If AD Attribute doesn't exist create one.
    if(!(Get-ADObject -SearchBase "$((Get-ADRootDSE).SchemaNamingContext)" -Filter {lDAPDisplayName -eq $Name})) {
    New-ADObject -Name $Name -Type $type -Path $schemapath -OtherAttributes $attributes
    Write-host "AD attribute $Name has been created." -ForegroundColor Green
    }
    Else {Write-host "AD attribute $Name allready exist in AD." -ForegroundColor yellow}
 
}

#START Script

#Get AD Schema details
$dse =  Get-ADRootDSE
$schemaPath = $dse.schemaNamingContext       
$type = 'attributeSchema'


#Create a New AD Schema Auxiliary Class for SecureMFA
$Name = 'SecureMFA'
$attributes = @{
            governsId = '1.3.6.1.4.1.54153.2.1000'
            adminDescription = 'SecureMFA Class to host OTP attributes'
            objectClass =  'classSchema'
            ldapDisplayName = $Name
            adminDisplayName =  $Name
            objectClassCategory = 3
            systemOnly =  $FALSE
            # subclassOf: top
            subclassOf = "2.5.6.0"
            # rdnAttId: cn
            rdnAttId = "2.5.4.3"
        }

#If Schema Auxiliary Class for SecureMFA doesn't exist create one.
if(!(Get-ADObject -SearchBase (Get-ADRootDSE).SchemaNamingContext -Filter {name -like "SecureMFA"})) {
New-ADObject -Name $Name -Type 'classSchema' -Path $schemapath -OtherAttributes $attributes
Write-host "A New AD Schema Auxiliary Class SecureMFA has been created." -ForegroundColor Green
}
Else {Write-host "Auxiliary Class SecureMFA allready exist in AD." -ForegroundColor Yellow}

#Add AD Schema SecureMFA Auxiliary Class To default User Class
$auxClass = Get-ADObject -SearchBase $schemaPath -Filter "name -eq `'$Name`'" -Properties governsID
$classToAddTo  = Get-ADObject -SearchBase $schemaPath -Filter "name -eq `'user`'"
$classToAddTo | Set-ADObject -Add @{auxiliaryClass = $($auxClass.governsID)}

#START Creating AD attributes

ADDADAttribute -Name 'sMFA-OTP-secret' -Description 'User Secret attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00001' -AttributeType String -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-logon' -Description 'User logon status attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00002' -AttributeType Int -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-lastlogon' -Description 'User laslogon attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00003' -AttributeType Time -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-logoncount' -Description 'User logoncount attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00004' -AttributeType Int -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-failedlogoncount' -Description 'User failedlogoncount attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00005' -AttributeType Int -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-failedlastlogon' -Description 'User failedlastlogon attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00006' -AttributeType Time -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-failedcode' -Description 'User failedcode attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00007' -AttributeType String -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-logonip' -Description 'User logonip attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00008' -AttributeType String -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-useragent' -Description 'User useragent attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00009' -AttributeType String -IsSingleValued $true
ADDADAttribute -Name 'sMFA-OTP-interval' -Description 'User interval attribute' -AttributeID '1.3.6.1.4.1.54153.2.1000.00010' -AttributeType Int -IsSingleValued $false

#Refresh AD schema
$dse.schemaUpdateNow = $true
Write-host "Refreshing AD Schema." -ForegroundColor Green

[bool]$reset = $false
#START Adding AD Schema Attributes to User Class:

@("sMFA-OTP-secret","sMFA-OTP-logon","sMFA-OTP-lastlogon","sMFA-OTP-logoncount","sMFA-OTP-failedlogoncount","sMFA-OTP-failedlastlogon","sMFA-OTP-failedcode","sMFA-OTP-logonip","sMFA-OTP-useragent","sMFA-OTP-interval") | foreach {    
    $SchemaAttribute = $_.trim()
    $reset = ADDADSchemaAttributetoClass $SchemaAttribute
    if($reset) {Write-host "AD attribute $SchemaAttribute have been added into SecureMFA Auxiliary Class." -ForegroundColor Green}
    else {Write-host "AD attribute $SchemaAttribute has failed to add into SecureMFA Auxiliary Class. Please try again later when AD replication for attributes is completed across your environment." -ForegroundColor red}    
    }

#Refresh AD schema
$dse.schemaUpdateNow = $true

write-host "Custom sMFA attributes have been created. Please note that depending on AD replication policies it may take a while to show a new custom attribute for user object in AD when using GUI tools." -ForegroundColor Cyan
pause