Dissertation 06012419
Dissertation 06012419
Dissertation 06012419
GRZEGORZ K. SPYRA
MSC ADVANCED SECURITY AND DIGITAL FORENSICS
SCHOOL OF COMPUTING
AUGUST 2012
SUBMITTED IN PARTIAL FULFILMENT OF THE REQUIREMENTS
OF EDINBURGH NAPIER UNIVERSITY FOR THE DEGREE OF MASTER OF SCIENCE
IN ADVANCED SECURITY AND DIGITAL FORENSICS
AUTHORSHIP DECLARATION
I, Grzegorz K. Spyra, confirm that this dissertation and the work presented in it are my
own achievements.
1. Where I have consulted the published work of others this is always clearly attributed;
2. Where I have quoted from the work of others the source is always given. With the
exception of such quotations this dissertation is entirely my own work;
3. I have acknowledged all main sources of help;
4. If my research follows on from previous work or is part of a larger collaborative
research project I have made clear exactly what was done by others and what I have
contributed myself;
5. I have read and understand the penalties associated with plagiarism;
6. I confirm that I have obtained informed consent from all people I have involved in the
work in this dissertation following the School's ethical guidelines;
Signed:
Grzegorz K. Spyra Zrich, 20 August 2012
Matriculation no: 06012419
ii
The University may make this dissertation, with indicative grade, available to others
The University may make this dissertation available to others, but the grade may not be disclosed
iii
ABSTRACT
Currently one of the most popular IT trends is to migrate into the cloud computing, and a
security engineer who integrates enterprise infrastructure with the cloud needs to provide the
best possible security level to protect the digital identity against unauthorized use. The task of
cloud-based authentication can be very simple as there are several products on the market that
are ready to take responsibility for all processes around authentication. However enterprise
identity management it is not only an authentication to one simple web page, where in more or
less secure manner system authenticates who you are? and not only what you know? The
enterprise identity management models comprise of multiple components including enterprise
directory, provisioning component, workflow components and the privilege management
components. To effectively control enterprise identity authentication the implementation
requires efficient access control model like Role-based Security Access Control (RBAC) and
very scalable framework, which align with business and not only with IT systems.
This thesis aims is to evaluate the implementation of Role-based security for Oath
authentication model exposed as Identity as a Service (IDaaS) using Infrastructure as a Service
cloud-based server instance. It focuses on different aspects of digital identity, authentication,
RBAC and cloud computing, that are delivered in large enterprise. This thesis presents an
OAuth 1.0 authentication enabled system, and is compared with the commonly used in
enterprise Microsoft Integrated Windows Authentication model.
The Proof of Concept implementation is a framework that consists of SQL database, .Net
services and ASP.Net components. To deliver the model that will quickly adapt to new findings
made during writing this thesis and the model that will self-evaluate all the interconnected
components and technologies used, the dedicated authentication and authorization front-end is
implemented on top of the framework. The tests performed return either grant or deny access at
different stages of authorization flow. Scenarios created for model evaluation show how
different technologies with various configurations can adapt into the cloud across several
security boundaries with federated identity and RBAC.
TABLE OF CONTENTS
ABSTRACT
ACKNOWLEDGMENTS
1. INTRODUCTION
1.1. CONTEXT
1.2. AIMS AND OBJECTIVES
THESIS LAYOUT
1.2.1. LITERATURE REVIEW
1.2.2. HIGH LEVEL DESIGN
1.2.3. CLOUD-BASED IMPLEMENTATION AND LOW LEVEL DESIGN
1.2.4. EVALUATION
1.2.5. CONCLUSIONS
8
9
10
10
10
10
11
11
12
2.1. INTRODUCTION
2.2. DIGITAL IDENTITY AND IDENTITY MANAGEMENT
2.2.1. IDENTITY PROVISIONING
2.2.2. IDENTITY AS A SERVICE (IDAAS)
2.2.3. FEDERATED IDENTITY
2.2.4. CLAIMS-BASED IDENTITY
2.3. AAA IN CLOUD
2.3.1. INTEGRATED WINDOWS AUTHENTICATION
2.3.2. OAUTH
2.3.3. CLAIMS-BASED AUTHENTICATION
2.3.4. WHY DIRECTORY?
2.4. ROLE-BASED SECURITY
2.4.1. CONCEPT
2.4.2. RBAC VIA ABAC
2.5. XAAS
2.6. SECURITY CONCERNS
2.6.1. DATA PROTECTION ACT
2.6.2. PATRIOT ACT
2.6.3. SAFE HARBOR
2.6.4. PERSONAL DATA IN THE CLOUD
2.6.5. INTEGRATED WINDOWS AUTHENTICATION
2.6.6. OAUTH
2.6.7. OAUTH 1.0 VS 2.0
2.6.8. SOAP PROTOCOL VULNERABILITIES
2.6.9. RBAC MODEL STRENGTHS & VULNERABILITIES
2.7. CONCLUSIONS
12
13
14
17
19
20
22
22
24
28
30
32
32
33
34
35
35
36
37
37
37
38
38
38
39
39
41
3.1. INTRODUCTION
3.1.1. BACKGROUND
3.1.2. DESIGN GOALS
3.3. ARCHITECTURE
3.3.1. INTRODUCTION
41
41
43
44
44
3.4. DATA
3.4.1. INTRODUCTION
3.4.2. SCHEMA
3.5. CODE
3.5.1. INTRODUCTION
3.5.2. MODULES
3.5.4. INTERFACES
3.5.5. IDENTITY TYPES
3.6. DAILY OPERATIONS
3.7. INSTALLATION
3.7.1. IAAS
3.7.2. IIDMANAGEMENT
3.7.4. IPORTAL AND ENTERPRISE PORTAL
3.7.5. IADCONNECTOR
3.7.6. DEDICATED DATABASE
3.8. INTEROPERABILITY WITH OTHER SYSTEMS
3.9. SECURITY
3.10. OPEN ISSUES AND RECOMMENDATIONS
3.10.1. IADCONNECTOR
3.10.2. RBAC & ABAC TRANSACTIONS SECURITY
3.11. CONCLUSIONS
45
45
46
50
50
50
53
53
54
54
54
54
55
55
56
56
56
57
57
58
58
4. CLOUD-BASED IMPLEMENTATION
60
4.1. INTRODUCTION
4.2. SYSTEM CONFIGURATION
4.2.1. AMAZON EC2 CLOUD INSTANCE (IAAS)
4.2.3. MICROSOFT ACTIVE DIRECTORY DOMAIN SERVICES
4.2.4. OAUTH 1.0
4.2.6. INTEGRATED WINDOWS AUTHENTICATION
4.3. CLIENT SIDE
4.3.1. CLOUD INSTANCE ACCESS
4.4. ACTIVE DIRECTORY PROVISIONING
4.4.1. AD FOREST
4.4.2. DOMAIN STRUCTURE AND UNDERLYING OBJECTS
4.5. META-DIRECTORY
4.5.1. IIDMANAGEMENT
4.5.2. IADCONNECTOR
4.6. CONCLUSIONS
60
60
60
61
61
65
66
66
67
67
67
68
68
69
72
5. EVALUATION
73
5.1. INTRODUCTION
5.2. METHODOLOGY
5.3. NEXT GENERATION VS TRADITIONAL AUTHENTICATION APPROACHES
5.3.1. WINDOWS INTEGRATED AUTHENTICATION
5.3.2. OAUTH
5.3.3. BRIEF SUMMARY
5.4. RBAC & ABAC
5.4.1. ROLE-BASED ACCESS CONTROL SCALABILITY
5.4.2. BRIEF SUMMARY
5.5. CONCLUSIONS
73
73
74
74
77
80
80
80
84
84
7. CONCLUSIONS
86
86
87
87
88
APPENDIXES
APPENDIX A
APPENDIX B
APPENDIX C
APPENDIX D
APPENDIX E
APPENDIX F
APPENDIX G
APPENDIX H
APPENDIX I
APPENDIX J
APPENDIX K
A
SUPERVISION
DIARY
PROFESSIONAL RESEARCH
GANTT CHART
EC2 AMAZON CLOUD SERVER INSTANCE SPECIFICATION
IIDMANAGEMENT DATABASE SCHEMA DESCRIPTION
IADCONNECTOR DATABASE SCHEMA DESCRIPTION
IPORTAL DATABASE SCHEMA DESCRIPTION
STORED PROCEDURES
PROVISIONING.CMD
IADCONNECTOR
A
B
E
R
U
V
W
X
Y
EE
GG
LIST OF FIGURES
FIGURE 1 IDENTITY PROVISIONING TRADITIONAL MANUAL APPROACH
15
FIGURE 2 IDENTITY PROVISIONING AUTOMATED APPROACH
15
FIGURE 3 CLOUD-BASED IDENTITY PROVIDER SERVICE
18
FIGURE 4 CONFIDENTIALITY, INTEGRITY AND AVAILABILITY IN IDAAS
18
FIGURE 5 INFRASTRUCTURE WITHOUT FEDERATED IDENTITY (BLACKBRIDGE).
19
FIGURE 6 FEDERATED IDENTITY INFRASTRUCTURE WITH CENTRAL FIM HUB (BLACKBRIDGE)
20
FIGURE 7 CLAIMS BASED IDENTITY ENTITIES (BERTOCCI, 2011)
21
FIGURE 8 CLAIMS-BASED IDENTITY AUTHENTICATION FLOW
22
FIGURE 9 INITIAL TOKEN ISSUE PROCESS IN IWA
22
FIGURE 10 AUTHENTICATION USING CACHED ACCESS TOKEN
24
FIGURE 11 AUTHENTICATION USING CACHED CREDENTIALS WITH TWO DOMAINS IN TWO-WAY TRUST
24
FIGURE 12 RESOURCE OWNER GRANTS RESOURCE ACCESS TO THE CLIENT (HAMMER, RECORDON, & HARDT, 2012)
26
FIGURE 13 CLIENT REQUESTS ACCESS TOKEN FROM AUTHORIZATION SERVER (HAMMER, RECORDON, & HARDT, 2012) 27
FIGURE 14 CLIENT CLAIMS RESOURCE ACCESS FROM RESOURCE SERVER WITH VALID ACCESS TOKEN (HAMMER, RECORDON, &
HARDT, 2012)
27
FIGURE 15 CLAIMS-BASED AUTHENTICATION (BERTOCCI, 2011)
29
FIGURE 16 CLAIMS-BASED AUTHENTICATION WITH SSO (BERTOCCI, 2011)
30
FIGURE 17 OBJECT LOCATION WITHIN DIRECTORY INFORMATION TREE (DIT) (ANDERSEN, 2008)
31
FIGURE 18 ABAC RULES SET FILTERING ASSETS ACCESS BASED ON ACCOUNTS ATTRIBUTES
34
FIGURE 19 CLOUD ABSTRACTION LAYERS; THE BEST-KNOWN SERVICE MODELS (BUCHANAN, 2010)
35
FIGURE 20 MIND THE GAP PHRASE FROM LONDON UNDERGROUND WITH LOGO USED BY DEUBY AT AL (DEUBY, 2011) 37
FIGURE 21 IDAAS IMPLEMENTATION WITH IIDMANAGEMENT AND IADCONNECTOR (FIM, IAM AND LDAP CONNECTOR) 41
FIGURE 22 IIDMANAGEMENT - ABAC ENGINE THAT ENFORCES RBAC RULES
42
FIGURE 23 OAUTH FLOW BETWEEN IPORTAL AND ENTERPRISE PORTAL
43
FIGURE 24 IIDMANAGEMENT TABLES REQUIRED TO FEDERATE IDENTITY
47
FIGURE 25 IIDMANAGEMENT ABAC ENGINE TABLES
48
FIGURE 26 IADCONNECTOR INVENTORY SCHEMA
49
FIGURE 27 IADCONNECTOR SYNC META-DATA AND CONFIGURATION TABLES
50
FIGURE 28 BLOCK DIAGRAM OF IADCONNECTOR SERVICE MODULES ACTIVITY FLOW
52
FIGURE 29 DEVDEFINED.OAUTH LIBRARIES (VISUAL STUDIO 2010 SOLUTION EXPLORER)
61
FIGURE 30 DEVDEFINED.OAUTH-EXAMPLES (VISUAL STUDIO 2010 SOLUTION EXPLORER)
62
FIGURE 31 IPORTAL AND ENTERPRISEPORTAL POOLS
64
FIGURE 32 ACTIVE DIRECTORY USERS AND COMPUTERS CONSOLE PROVISIONED DOMAIN STRUCTURE
68
FIGURE 33 ENTERPRISE PORTAL WELCOME PAGE
74
FIGURE 34 IWA LOCAL TEST ACCESS GRANTED
75
FIGURE 35 IWA CLOUD TEST ACCESS DENIED
75
FIGURE 36 IWA LOCAL TEST WITH KERBEROS SECURITY TOKEN; USER IS A MEMBER OF SECURITY GROUP ACCESS GRANTED
76
FIGURE 37 IWA LOCAL TEST RESOURCE OWNER SPYRA REMOVED FROM THE SECURITY GROUP
77
FIGURE 38 IWA LOCAL TEST KERBEROS TICKET ENTITLEMENTS BASED ON SECURITY GROUPS MEMBERSHIPS ACCESS
GRANTED
77
FIGURE 39 OAUTH CLOUD-BASED AND LOCAL TESTS; STEP1 - SUCCESSFULLY REDIRECTED TO IP FOR AUTHENTICATION
78
FIGURE 40 OAUTH CLOUD-BASED AND LOCAL TESTS; STEP2 ACCESS CONTROL PAGE RO SUCCESSFULLY AUTHENTICATED 79
FIGURE 41 OAUTH CLOUD-BASED AND LOCAL TESTS; STEP3 ACCESS GRANTED
79
FIGURE 42 OAUTH CLOUD-BASED AND LOCAL TESTS; TOKEN EXPIRED ACCESS DENIED
80
FIGURE 43 ABAC ENFORCES RBAC RULES AND BILL ACCOUNT CANNOT CONTROL THE RESOURCE
83
FIGURE 44 ABAC ENFORCES RBAC RULES; OAUTH ACCESS GRANTED
84
FIGURE 45 IAAS CLOUD SERVER INSTANCE SPECIFICATION
U
LIST OF TABLES
TABLE 1 ESTIMATE NUMBER OF INSTANCES OF EACH PART
TABLE 2 IIDMANAGEMENT DATABASE TABLES
TABLE 3 IADCONNECTOR DATABASE TABLES
TABLE 4 XML CONFIGURATIONS
TABLE 5 ADVANCED SERVICE CONFIGURATION
TABLE 6 AUTHENTICATION TESTS SUMMARY
TABLE 7 CURRENT FEDERATED IDENTITY INFORMATION
TABLE 8 CURRENT ABAC RULE SET
TABLE 9 UPDATED ABAC RULE; ADDED LEGAL & RISK DEPARTMENT
TABLE 10 ABAC ENGINE ENFORCED RBAC RULE BASED ON NEW DEPARTMENT IN THE RULE SCOPE
TABLE 11 FEDERATED IDENTITY FRAMEWORK TEST RESULTS
TABLE 12 IIDMANAGEMENT DATABASE DESIGN DETAILS
TABLE 13 IADCONNECTOR DATABASE DESIGN DETAILS
TABLE 14 IPORTAL IADCONNECTOR DATABASE DESIGN DETAILS
44
69
70
71
71
80
82
83
83
83
84
W
X
X
ACKNOWLEDGMENTS
I want to start by thanking my wife and daughter for their patience while I work on this
thesis. Thank you Olivia for being patient and compassionate. I know these are very first
moments for us, you as my 6 months old daughter and me your father. Hope one day we will be
able to discuss the latest information security trends.
I would like to thank my supervisor Prof. William Buchanan for all the ideas he shared with
me. Without him this thesis would not have the current shape and I would miss many important
contexts so crucial for deliverables.
Professionally, I want to thank my manager John M. for all the support I got from him. All
the meetings with third parties you invited me to related to FIM and Claims-based
authentication helped me to see federated identity in reach enterprise context.
1. INTRODUCTION
1.1. CONTEXT
The Internet evolved from era where it was mostly used as a medium that gives access to
unrestricted data to an era of cloud computing, where the Internet is more adapted for enterprise
use. Cloud implementations of authentication infrastructures are currently widely discussed due
to their nature (Deuby, 2011). Business processes that previously were integrated internally into
enterprise are now exposed in cloud computing via the Internet. The Confidentiality,
Availability and Integrity (CIA) triad, which is a base of any security measure, can be
evaluated against number of new threats related to authentication for cloud computing. Rolebased security (also called Role-based access control RBAC) implementations for
authentication and authorization delivered with cloud computing need to offer some
equivalence, and give even more enhanced functionality than internally integrated enterprise
implementations. RBAC, one of the non-discretionary access control types, is the most
innovative identity and access management (IAM) model since Discretionary Access Control
(DAC) and Mandatory Access Control (MAC) access control types were released (Sandhu,
Coyne, Feinstein, & Youman, 1996).
OAuth next to RBAC is another important, next generation technology that allows secure
access to user data across different sites without need for username and password exchange.
This authentication model empowers enterprises to securely access external resources like
Facebook, Tweeter, Google, Flickr etc. and also other enterprises (Hammer E. , 2010). OAuth
protocol was created to securely delegate rights to different clients across different platforms
independently from location, organization and business role. Its current implementation solves
many identity related issues that main market players who deal with customer identity were
facing for the last few years (Hammer E. , 2010). OAuth is also becoming more popular in
large enterprise implementations, and unlike Role-based security, OAuth is enterprise
independent.
RBAC implementations are often complex, as they require underlying meta-directory that
supports identity recognition and security entitlements control (Pohlman, 2003). These
implementations can be simple to adjust into Small Office Home Office (SOHO) also in
Small and Medium-Sized Enterprises (SMEs), however they are becoming complex and are
often not efficient when it comes to Large Enterprises (LEs) implementations, where security,
RBAC authentication and operations performance constraints play role.
All three elements: authentication, Role-based security and cloud computing, are separate
terms in Next Generation Authentication Infrastructures with Role-based Security for Cloud
Computing subject however implemented together into the cloud instance will act as Identity
as a Service (IDaaS) cloud-based service. Each of these terms comprise distinct technology
therefore scalability, efficiency and security level of a model where all three were integrated
together need to be evaluated and the model adjusted to ensure the highest possible efficiency
and security level in enterprise.
Perform a literature review around the key areas of IDaaS for large enterprise and data
protection.
Create a high-level design for the testing and evaluation system that will be used. This will be
supported with critical analysis of different implementation models that are available on the
market and delivered as ready out-of-the-box products.
Implement and evaluate the practical aspects of possible RBAC system and compare, and
evaluate directory with database model as a complete meta-directory system. This will
evaluate two authentication models: OAuth and Integrated Window authentication separately,
with and without RBAC. Along with the identity management framework it aims to create
heterogeneous implementation for federated identity where different authentication models are
used. This will show how next generation authentication infrastructures like OAuth meet IT
market requirements, and also how RBAC aligns with business and how both OAuth and RBAC
can efficiently integrate into complex system environment like we have in large enterprise.
THESIS LAYOUT
1.2.1. LITERATURE REVIEW
This chapter is dedicated to critical evaluation of existing Identity Management models
showing possible implementations of authentication infrastructures that can be delivered in
cloud computing. It shows aspects of identity provisioning with Role-based security as a way
of secure, effective and business oriented access control. It also compares Identity Management
and RBAC operations carried out in Microsoft Active Directory and Microsoft SQL database.
In conclusion is outlines the operations are more suitable for directory application, and which
perform best with database applications. Additionally this chapter shows how the next
authentication infrastructures can align with both enterprise and external services like Windows
Live ID, Google, Yahoo, Facebook, and so on, especially when we consider not only technical
aspects of implementation, but also Information Security with its CIA triad.
1.2.2. HIGH LEVEL DESIGN
The High Level Design chapter specifies the design goals, and outlines the model design
details from high-level perspective. It provides a solid background for the implementation, and
includes the directory structure and provisioned identities details, such as organization structure
and identity object counts. It also outlines self-developed cloud-based implementation of
Identity as a Service with RBAC and ABAC systems based on Microsoft Active Directory
(AD). To test the authentication infrastructure for both implementations used OAuth 1.0
protocol and a basic client application.
This chapter thus presents the complete system architecture with all components. It describes
the system interfaces, communication between components, data operations, and code modules
with internal functions, also cloud instance hardware and software details.
1.2.3. CLOUD-BASED IMPLEMENTATION AND LOW LEVEL DESIGN
The Cloud-based Implementation chapter consists of system implementation details such as:
directory provisioning steps; database structure scripts; MS Server Roles installation and
configuration details; MS SQL DB stored procedures and functions scripts; supporting custom
Windows Services; and scripts that are used for meta-directory and Identity Management. All
settings specific for the Proof of Concept (PoC) implementation are in this chapter, and all the
design aspects that are not covered in HLD section are thoroughly described in LLD thesis
chapter.
10
Complete .Net source code, MS SQL stored procedures and functions, supporting scripts can
be found in Appendixes. In LLD section only selected code parts are used that are required to
justify the design decisions.
1.2.4. EVALUATION
The Evaluation chapter covers testing methods used to validate data and data operations from
created system prototype. This chapter is crucial as this is where two different RBAC
implementations are evaluated. The prototype system provisioned is SME size rather than LE
size, although operations used to control security entitlements of digital identities can show
issues that need to be addressed when delivering product mature for the destination market.
1.2.5. CONCLUSIONS
The Conclusions chapter summarizes all previous sections and shows whether and how
the aims and objectives were met. All possible enhancements to the prototype and
implementation suggestions are covered here, as they are not required for the PoC of this
thesis.
11
12
Lothian Buses company from Edinburgh released Smartcard type bus ticket that stores information
about your bus travel entitlements. It uses a card owner photo at the top of the card to validate if the
cardholder legally uses the card.
1
13
operations that the student could perform on bank systems due to owned privileges is very high
and the bank loss could be estimated then in billion pounds.
The problem highlighted here is a very common in Identity and Access Management
systems. In IAM we do not have students, but privileged identities that hold permissions over
resources and as per our example with the student these permissions remain even if security
entitlements were taken away. We also have scenarios where access control system does not
enforce separation of duties on controlled identities (see Section 2.6.9). Having the separation
of duties enforced in our example with a student, we can be sure that student would not be able
to cause any harm as would not be able to initiate and complete any transaction by himself.
With right identity authorization and authentication technique and proper identity provisioning
procedures in place, implemented beside with identity Role-based security operations, any of
the scenarios with student breaching the system rules would not have place.
2.2.1. IDENTITY PROVISIONING
2.2.1.1. Enterprise Processes
Identity provisioning is an important process in every enterprise. It is not only specific to the
enterprise, as also in popular social media portals, accounts are provisioned with some default
settings. In enterprises, identities can be provisioned differently depending on the employee
location, department, role in this department or customer contract terms and conditions, while
in social media portals during provisioning identities may be differentiated by customer
country, interests, or language. Provisioning automates many processes that before were
manual processes of creating accounts and granting access to these accounts over resources
across the enterprise (see Figure 1, Figure 2).
Figure 1 outlines the traditional provisioning, where the process with several different actors
that are involved in identity provisioning. We can start with HR Officer who registered newlyhired employee in HR System. The HR Officer sends email to Help Desk Analyst and requests
specific accounts to be created for the new employee and specifies what is the organizational
role of the new employee. Based on HR instructions, the new system accounts (identities) are
created, however there are several access rights related to this organizational role that
Help Desk Analyst could not grant. This is where System Administrator role is required in
provisioning process. Help Desk Analyst sends email to System Administrator to permission
the newly created accounts over several resources and systems.
14
15
The automated provisioning process is fairly simple and actually the HR Officer is the only
actor that has to perform some manual actions in this system. The New Employee record is
picked up by provisioning engine and automatically based on the organizational role that was
assigned to the employee record the relevant set of new accounts is created in all required
systems and are automatically permissioned over systems assigned to the default departmental
role.
Both models are close to Role-based security, although these examples show how it works in
many organizations. Currently provisioning systems try to reduce the amount of systems where
the account is provisioned, and rather than this, provision one corporate identity into the
directory or the database and via either Identity Provider, or using direct identity meta-data
access perform operations of Authentication and Authorization.
Provisioning helps business to quickly adapt to new requirements like Internet and cloud
computing. It also helps the enterprise to reduce the time it takes to implement a new physical
IT infrastructure changes and align to various changes of interconnected systems. It is not only
a process that takes responsibility for simple operation of new account creation as its
functionality spreads beyond account creation process. We can define provisioning as a
functional extension of Authorization. Both consist a natural combination as provisioning
process enforces user account and rules creation while authorization enforces these rules
(Pohlman, 2003).
Provisioning systems are critical infrastructure components because this is where all the
processes like account creation, enablement, disablement and deletion lie (Pohlman, 2003).
With proper identity provisioning system that has relevant underlying access control model
(like RBAC) the student from our example (see Section 2.2) would not breach the bank access
control rules because provisioning would take care of student department change and reflect it
in correct access rights amendment. By automating the timely provisioning and de-provisioning
of user accounts and security entitlements, organizations can meet privacy and compliance
requirements and also reduce the risk of unauthorized access (Mather, Kumaraswamy, & Latif,
2009).
2.2.1.2. Enterprise Directory
Identities provisioning requires a strong back-bone not only to suit the basic indexing rules to
access identity, store properties of the identity or to perform identity operations in transactional
16
manner but also, what is the most important, to locate the newly provisioned identity in the
right place of the organizational structure, grant generic permissions based on the identity
purpose and define the identitys role within the structure. This is where directory
implementations are becoming the most powerful and efficient (Arkills, 2003).
Directory is hierarchical and structured as a tree. This is a place where all identity
information about employees, suppliers, customers and assets. Identity provisioning into LDAP
makes the provisioning process straightforward in terms of self-defining identity security role
within the enterprise that is represented with structured directory.
2.2.2. IDENTITY AS A SERVICE (IDAAS)
IDaaS is one of the services that are delivered with cloud computing. This architecture
exposes organizational IAM systems and processes with the cloud. In other words all processes
that were internally implemented into the enterprise can now be outsourced into third party
IDaaS providers (Mather, Kumaraswamy, & Latif, 2009). By implementing ready IDaaS
models the enterprise can save time and money required to delivered own federated identity
management infrastructure. The federated identity enablement it is not only related to
implementation of the system that supports FIM but also complex and secure network
infrastructure that consists of dedicated perimeter networks designed to provide FIM services.
From technical perspective IDaaS is nothing else than Software as a Service (SaaS) cloudbased service dedicated for Identity Management that acts as Identity Provider (IdP). IDaaS
acts as a proxy for the organization handling cloud services access requested by identities (see
Figure 3). IDaaS stores identities in a trusted identity store that can be synchronized with
organizational directory (Mather, Kumaraswamy, & Latif, 2009).
When the enterprise implements Cloud-based Identity Service Provider all Cloud-based
Service Providers (CSP) should delegate authentication to the newly established IdP. This
model delivers Single sign-on (SSO) functionality as every authentication is done once prior to
any further cloud services access.
For the enterprise the migration into IDaaS model might be relatively simple, although in
large sized enterprise there are always requirements to support extensive auditing and reporting
functionality (Mather, Kumaraswamy, & Latif, 2009). When it comes to IdP evaluation with
Confidentiality, Integrity and Availability (CIA) triad (see Figure 4) there is much more to
mitigate than simple Identity Management systems migration into the IDaaS.
17
(WAAD), which integrate with enterprise MS Active Directory infrastructures and provide
cloud-based authentication services. IdP can be also placed into the cloud under IaaS cloud
server instance and actually act as the IDaaS enabled system. This custom approach is a part of
this dissertation and will be explained in High Level Design and Cloud-based Implementation
sections.
2.2.3. FEDERATED IDENTITY
Federated Identity is a term that responds to demand for digital identity to step beyond the
enterprise boundary. Federated identity is a key IAM component that links digital identities
across domain boundaries (Mather, Kumaraswamy, & Latif, 2009). Separate secure domain
boundaries (see Figure 5) can store digital identity information separately in directories or other
identity repositories, also can implement various meta-directories to store the identity metadata, however as long as there is no concept of federated identity these security boundaries will
not go beyond the organization that implemented the identity management system (Windley,
2005).
19
different repositories may store information about one the same identity that is not consistent,
while other identity information might be just redundant. Centrally managed repository did not
solve the problem as could not handle cross-organizational authentication and authorization
(Windley, 2005). The federated identity solves the identity problem, as it does not restrict the
view on the identity infrastructure to one central homogeneous repository (Windley, 2005).
Federation provides processes and supporting technologies to enable cooperation among
different digital identity stores so the identity is linked regardless of its repository location.
These identity linkages are controlled with FIM systems (Windley, 2005) and they can be
enforced by pre-defined system rules or also can be amended manually in exceptional cases.
Because the identity is linked federated identity can flexible authenticate users from partner
organizations (see Figure 6) and authorize them to access protected resources (Windley, 2005).
For this thesis used the FIM concept in developed IDaaS model where implemented
federated identity model with linked digital identities from MS Active Directory through SQL
based meta-directory.
20
This statement simplifies, however summarizes the idea behind the claims-based identity.
When look at the conceptual model (see Figure 7) can see four entities: Subject,
Identity Provider, Relying party and a claim. The natural way corresponds to live examples
where e.g. student (Subject) receives student ID (Claim) from the university (Identity Provider)
so student can now get into the club (Relying Party) with the new ID as a claim that stores
information about the student age (the claim property). The club does not have to verify if the
student actually meets the age criteria because the club as a Relying Party it is relying on
somebody else that done the verification in the first place (Identity Provider) and issued the
student ID.
21
identity information required to authenticate the identity (Deuby, 2011). The complete
authentication flow is described in the Claims-based Authentication section.
The hashed credentials are provided to the web server using cryptographic exchange and the
user is not prompt to provide the username and password as long as the stored credentials can
22
pass the authentication (see Figure 9). In case if authentication exchange fails the user is
prompted to provide Windows credentials for IWA flow (De Clercq, 2004).
The Integrated Windows authentication really consists of two authentication protocols:
NTLM and Kerberos. These protocols are used to call Security Support Providers. The specific
to the IWA is that it uses HTTP protocol to transport messages (De Clercq, 2004). The reason
why the transmission with SSP is not secured is that in IWA model the secure credentials are
not actually exchanged but only the hash is a subject of the authentication. Both NTLM and
Kerberos are widely used in most of the enterprise authentication implementations, however
both are either not secure or not scalable.
The NTLM v1 protocol does not provide any cryptography for authentication messages
transmission. Its successor NTLM v2 is much more secure (Boeynaems, 2010), however
Kerberos is faster and deliver several other features that are missing in both NTLM
implementations (De Clercq, 2004). The major advantage of NTLM over Kerberos is that the
NTLM can successfully authenticate in heterogeneous infrastructures while Kerberos must be
registered in a domain that is in a trust-relationship with a domain that web server is a member
of (Boeynaems, 2010).
The new authentications techniques (see Section 2.3.3) try to solve problems of their
predecessors but are still not well established and in most of the cases are not delivered as outof-the-box product.
Integrated Windows authentication is best suited for authentication within the enterprise with
intranet Web sites, although this technology is not scalable for the Internet and cloud services
(De Clercq, 2004).
23
Figure 11 Authentication using cached credentials with two domains in two-way trust
2.3.2. OAUTH
As per the example with the student (see Section 2.2) a very common problem with
authentication and authorization protocols is that they do not provide the most secure service in
24
order to protect resources. The Kerberos, one of the most popular authentication methods that
are currently widely used behaves exactly like the Ridacard system and does not validate the
token itself since it is issued. Security Access Token (SAT) that is created when user login into
Microsoft Windows system machine stores security information what can do about the
identity (user account). From the moment that the user logged into the machine the user
receives list of security groups that are stored in SAT, which exists as long as the user remains
logged in. The SAT is secured and not easily accessible, however the problem appears when
we grant user new security entitlement via Security Group. The security change will not reflect
the SAT till the user does not logoff from the system. This might not be a problem as we can
inform the user that in order to have the security entitlements refreshed has to logoff and log
back on again, although what if we remove the user from the security group. If the user should
not have access to some network resource anymore and the security entitlement removal was
done as an emergency change because there is a suspicion that the identity performs some
malicious operations that might be harmful for the organization, the access level of the identity
remain unchanged. The SAT will not reflect the security change on time and it will remain
valid for the user as long as the user session exists.
This problem might not be that serious as long as we have a control over what happens in our
organization. What if we start federating with other organization where many internal processes
might be very different and may not have the same information security culture as we managed
to maintain?
The Kerberos authentication reached its limits (see Section 2.3.1) and it does not respond to
latest IT market demands anymore. In era of cloud computing and distributed services, where
different web-based applications needs to exchange information in identity context (Google,
Flickr, Twitter, Facebook, Linkedin) and where third-party applications interconnect with
multiple services via APIs there is a demand for a new set of protocols that will address the
issues that older protocols can not address anymore (Hammer E. , 2010).
The OAuth was designed to solve many security and scalability problems of authentication
and authorization infrastructures. The most significant change to the authentication model that
came with OAuth protocol is completely different approach to credentials exchange. Using
OAuth users can grant third-party access to secure resources without need of username and
password exchanged. OAuth delivers not only the framework to build authentication and
authorization system but also a secure standard, which defines various access control features
25
(Hammer, Recordon, & Hardt, 2012). The OAuth was created to work over HTTP protocol
what makes it easily adaptable for any Internet and cloud-based web-services, which need to
interconnect to securely share protected resources.
2.3.2.1. Beyond Client-Server
OAuth unlike other traditional client-server authentication models adds concept from
Discretionary Access Control model where the object owner controls the access to the object
(Hammer E. , 2010). The innovation introduced with OAuth is that resource owner is one of the
authorization entities that can act either as only resource owner or as both resource owner and
the client. The client is the one that needs to access the protected resource.
The resource owner is the subject that grants the resource access without sharing credentials
with client. This is processed using token and shared-secret match (Hammer E. , 2010). The
token is the alternative to credentials exchange and it is representing authorization issued to the
client. In order to access the resource, the client requests authorization grant from the resource
owner (see Figure 12).
The access grant unlike in scenario where resource owner shares credentials with the client,
represents specific scopes and access duration (Hammer, Recordon, & Hardt, 2012). These are
properties that are controlled by both the resource server and authorization server and are
represented as access token properties.
When the client receives the access token from Authorization Server it contacts the Resource
Server to claim the resource access with the valid access token (see Figure 14).
Figure 12 Resource owner grants resource access to the Client (Hammer, Recordon, & Hardt, 2012)
26
Figure 13 Client requests access token from Authorization Server (Hammer, Recordon, & Hardt, 2012)
Figure 14 Client claims resource access from Resource Server with valid access token (Hammer, Recordon, &
Hardt, 2012)
In the most bookish implementation of the OAuth protocol the three actors are defined that
are part of the authorization flow. This model is described as 3-legged model, where leg in
other words is the party involved in OAuth flow. Other implementations consist of two and
more actors and are called respectively 2-legged, 3-legged, n-legged implementations.
27
The OAuth as a framework gives developer the wide range of authorization system design
choices (Hammer E. , 2010).
It is not an easy task to adjust OAuth authentication model to traditional RBAC
implementations around authentication. The reason behind it is that Role-based security bases
access control decisions on the functions an identity is allowed to perform within an
organization (Ferraiolo & Kuhn, 1992). The enterprise implementation of OAuth authentication
with RBAC can be very simple (what will be proved in the Chapter 4) although to benefit from
all OAuth features we need to go beyond the enterprise.
This OAuth protocol implementations variations, same as Cloud-based authorization models,
opens new possibilities of doing things that were not possible within traditional authorization
and authentication infrastructures. This important specific of these next generation
authentication infrastructures make them suitable for various types of Role-based security
systems (Bertocci, 2011). E.g. the access can be controlled with RBAC for the group of clients
and enforced on the authorization server by refusing access token issue before the access is
explicitly granted based on other rules that have higher priority than simple resource owner
approval.
2.3.3. CLAIMS-BASED AUTHENTICATION
Claims-based identity model is a key of FIM implementations. It consists of a subject that in
most cases is a user who wants to access an application. The application can be a standalone
application, a Web site or any Web-based service. This part of the model in identity jargon is
called Relying Party or Service Provider (SP). The last element of the model is an Identity
Provider (IP) that knows about the subject and knows how to authenticate the subject. There
can be more than one IP introduced to the system, however in most cases at least one needs to
be always available. In spite of that IP is an abstract role it has strictly defined functions, which
require system components such as: directories, identity repositories and authentication systems
(Bertocci, 2011). Security Token Provider (STS) is also one of the IP components. It is nothing
else than a specialized Web service, which has only one dedicated function to issue security
tokens.
The claims-based authentication in the simplest scenario (see Figure 15) starts with a subject,
a user who tries to access web-based application (Relying Party A at Figure 15). The user sends
HTTP GET command to the web-based application (RP A). Application redirects the user to
28
Security Token Service for authentication. When STS authenticates the user it issues
Security Token (ST) and send it back to the user. Having ST the user can go back to the webbased application with the valid ST and access the service (Bertocci, 2011).
Federated identity can exchange identity related data across security boundaries using claims,
assertions and access tokens. In a traditional approach directory (LDAP, and so on) defines
security domain for the enterprise and acts as an identity provider for this enterprise. In
federated identity scenario the entire enterprise that provides identity information acts as an IP
(Deuby, 2011).
Claims-based
authentication
introduces
another
important
functionality
for
FIM
infrastructures that is called Circle of Trust. CoT is a name used to describe scenario where two
or more SPs trust the same IP in order to share Digital Identity information. This is a part of
Single sign-on implementation where different parties can share the digital identity information
so the end-user does not have to authenticate itself again with IP.
In claims-based authentication model SSO is nothing else than use of traditional browser
cookies with a bit of trust management (Bertocci, 2011).
29
In SSO scenario (see Figure 16) the user when reach the STS is already authenticated with it
(see Figure 15) because the authentication has been already completed when the user was
accessing Relying Party A in previous example. STS does not have to initiate the authentication
flow again it only releases new sequence number and sends the Security Token back to the user
so the user can successfully access the Relying Party B (Bertocci, 2011). This authentication
flow is completely transparent for the end-user and the process works even better in practice as
there are session cookies involved. This is very short presentation how claims-based
authentication works in practice and how it delivers SSO functionality.
2.3.4. WHY DIRECTORY?
Directories deliver functionality that is not available in transactional databases what includes
hierarchical structure with objects access management that perfectly integrates with this
hierarchy. This specific security mechanism, where access can be controlled with extreme
granularity, which scales to object attribute level, comprises integrated part of any directory.
One of the most popular directory roles is being as a source of an authentication (Pohlman,
2003). IAM and FIM systems make use of directories to authorize resource or web-based
applications access. Because the directory is a security boundary for contained objects and
interconnected systems and due to its internal design and auditing functionality it is the most
common element of every large enterprise infrastructure and any organization that protects
resources and control access of registered identities.
30
Applications enablement
(Pohlman, 2003)
Currently the X.500 standard is the most commonly used directory data structure standard
used in directories implementation. This standard defines several protocols although these are
not
in
scope
of
this
thesis.
The
one
that
is
important
to
mention
is
Lightweight Directory Access Protocols (LDAP). This standard provides an open directory
access protocol, which inherits X.500 data model, however is much more efficient than its
predecessor Directory Access Protocol (DAP). LDAP is highly scalable to a global size with
millions of entries that are organized in secured and self-defining structures (see Figure 17).
Successfully deployed directories are scalable enough to be used in Small and Medium
Enterprise (SME) and in Large Enterprise (LE) (Pohlman, 2003).
Figure 17 Object location within Directory Information Tree (DIT) (Andersen, 2008)
The most popular implementation of LDAP is Microsoft Active Directory (Andersen, 2008).
MS AD provides wide range of services that use LDAP concept and delivers products that use
MS AD to control data access. MS AD has underlying flat database Extensible Storage Engine,
which is based on Jet databases that were used in other Microsoft products in early 90s
(Maples, 2008).
31
Objects stored in MS AD are having unique GUIDs, however these identifiers are relatively
large in MS implementations because GUID takes 16 bytes of memory that is why MS AD uses
distinguished name tags (DNT), which are unique within MS AD forest security boundary and
take only 4 bytes of memory (Maples, 2008). This internal MS AD structure is important to
understand, as this is crucial to deliver efficient meta-directory framework for IAM and FIM
that can scale to LE sized organizations (see Section 3.4.2.2).
Currently one of the most challenging tasks related to MS AD is to successfully place it in
the cloud. Organizations that use MS AD integrate it with many organization systems and
processes such as Business Continuity Plan. Internal implementations are designed to deliver
highly available system that enables fail-over functionality across different locations. This
functionality is a part of MS AD and is always considered when planning and deploying
MS AD infrastructures. Microsoft recently delivered a new cloud-based IDaaS service called
Windows Azure Active Directory to address demand for MS AD as IDaaS service (Sean,
2012).
32
For each subject, we define active role as the one that is currently being used by the subject
Subject may be entitled to execute transactions and the following predicate is true when subject s
can execute transaction t
Using above formal description it can be deducted that role can be compound of set of
transactions that identity can perform in organizational context.
Authentication infrastructures with Role-based security are not new in IT, although cloud
implementation requires authentication to meet cloud client needs as well as RBAC model
specific requirements (Pohlman, 2003).
2.4.2. RBAC VIA ABAC
Every account or asset has attributes that tell something about it. These attributes of account
or asset objects are specific for the context of these objects. Such properties through
comparative processing of organizational knowledge about the object such as location or
description, or situational data such as date and time when account accessed the asset (e.g. user
logged into the system), the Identity & Access Management system can take access control
action and decide whether object is authorized to perform specific activity in the secured
Attributes-Based Access Control (ABAC) infrastructure (OConnor & Loomis, 2010).
ABAC can be used to leverage account information and contextual information to securely
control access. This approach relies on other systems that control identity and resource access
that is why consistence of processed data will impact the quality of Attributes-based security
system. Having reliable identity provisioning system, which can rapidly replicate changes
related to identity within organizational context can make ABAC a powerful access control
model, which unlike RBAC can be easily exposed outside organization. RBAC cannot provide
sufficient level of access control security, as the identity from outside the enterprise cannot be
term used by Ferraiolo et al refers to bindings of transformation procedure and data access. In this
convention when we take savings deposit transaction that updates a savings database and transaction
file Read savings file is a valid transaction while Read is not.
2
33
matched with any specific internal role what would give granularity of transactions which can
be performed by digital identity. With authorization engine created as a hybrid of the RBAC
and ABAC models, the delivered system leverages the best of each (see Section 3).
Figure 18 ABAC rules set filtering assets access based on accounts attributes
2.5. XAAS
XaaS is an acronym that refers to Anything-as-a-(Cloud)Service. Cloud computing is a term
used to describe all different types of applications and XaaS services that are accessed with
Internet protocols and networking standards. Cloud computing is using virtualized resources
that are located on a distributed networks (Sosinsky, 2011). XaaS services are one of the cloud
concepts that aimed to deliver pay-as-you-go customer experience (Sosinsky, 2011). The three
early cloud computing models are Infrastructure as a Service (IaaS), Software as a Service
(SaaS) and Platform as a Service (PaaS) (see Figure 19), however as cloud computing matures
several other models were introduced like Hardware as a Service, Identity as a Service (IDaaS),
Complianc as a Service (CaaS), provisioning, storage, monitoring, communications and many
others (Sosinsky, 2011) are currently available as ready to use service delivered by cloud
computing providers.
IaaS model delivers ready infrastructure for application such as servers, networks, storage
and other components that are provided as manageable components. Another widely
implemented cloud service model is SaaS, which delivers ready to use applications such as
GoogleMail, Hotmail and many others. PaaS layer is mainly a part of Service Oriented
34
Architecture (SOA) service delivery model, which helps to develop applications (Buchanan,
2010).
The service models that are currently being delivered by different cloud providers are either
more generic and are compound of different cloud services sub-types or are specialized and
describe distinguish function of the service.
Figure 19 Cloud abstraction layers; the best-known service models (Buchanan, 2010)
35
Switzerland is one of the countries outside of the EEA, which has adequate level of data
protection (Information Commissioner's Office, 2010) required to transfer data from the EEA
or EU. Since Switzerland ratified the Convention for the Protection of Individuals with regard
to Automatic Processing of Personal Data in October 1997 it covers all basic principles of data
protection, which are mandatory to have adequate to UK DPA 1998 principals applied
(Information Commissioner's Office, 2010) (Information Commissioner's Office, 2010).
This act guaranties that personal data hold by any organization that comply with DPA is safe
and will not be send to somebody else, any individual or government without consent of data
subject. This also regulates cloud data flow as data stored under one jurisdiction where DPA
applies cannot be transferred outside this jurisdiction without Information Commissioner
consent (Desai & Johnson, 2012).
2.6.2. PATRIOT ACT
Uniting and Strengthening America by Providing Appropriate Tools Required to Intercept
and Obstruct Terrorism Act of 2001 (USAPA) also called USA Patriot Act of 2001 was signed
into law in October 26, 2001. One of the most controversial privacy-related legislation that has
several implications for cloud computing (Deuby, 2011). The act regulates private data access
under jurisdiction of USA. This law grants powers to law enforcements and intelligence
agencies to control electronic communication (Pohlman, 2003). These changes in U.S. law
caused many concerns among foreign governments, organizations and financial institutions
related to data flows. The Canada, that used to store data with providers located in USA
prohibited any government related data to be stored under U.S. jurisdiction (Deuby, 2011).
Many financial institutions located in European Union and Switzerland tightened rules
regarding secure data access and data replication by enforcing reviewed information security
policies or by introducing separation of duties (Ferraiolo & Kuhn, 1992) for all transactions
related to data access.
This problem of data protection in the cloud across different jurisdictions is very often
discussed and is the main concern, which stops enterprises from migrating into the cloud
computing. Leading cloud providers try to convince data commissioners to put trust in security
that comes with cloud computing, although USA Patriot Act of 2001 is the main argument
against the cloud computing (Desai & Johnson, 2012).
36
implementations, including Identity Providers location and security boundaries definitions still
constitute milestone for cloud computing to be a safe platform for everyone everywhere.
Cloud deployment might look attractive for Small and Medium Enterprise (SME), although
move into the cloud for Large Enterprises (LE) is followed by many information security
challenges related to data protection and jurisdictional, and organizational internal legal
compliance (Deuby, 2011).
Figure 20 Mind the Gap phrase from London Underground with logo used by Deuby at al (Deuby, 2011)
37
credentials on the page which is looking exactly the same as the one that user expects to log
onto. This problem was solved with Windows security token, which is obtained during client
logon process on a Windows system. Using IWA any resource can be accessed by the client
without providing additional credentials if it is joined to the MS domain where the client is
logged into or if it trusts the clients domain.
2.6.6. OAUTH
The OAuth protocol is same as most of the other authentication protocols vulnerable to
phishing attack. If the consumer sends user (resource owner) a site that looks like
authentication page of the users service provider then the attacker can intercept user
credentials. It is not the protocol problem but it is a general problem with all authentication
methods.
The OAuth protocol was designed to overcome eavesdropping and main-in-the-middle attack
and support non-secure HTTP protocol at the same time. OAuth can support secured HTTPS
channel where client-server can exchange plaintext messages, however HTTPS is not always
available. In order to ensure that the message can be send via HTTP in a secure manner OAuth
transmits secure data using RSA-SHA1 and HMAC-SHA1 (Hammer E. , 2010).
The same protocol implements basic technique to mark requests with 3nonce and timestamp.
This security approach protects requests against replay attack. Nonces are stored by the
Service Provider to protect the resource by making sure that requests are send only once and
they are received in a right order derived from the request timestamp (Hammer E. , 2010).
2.6.7. OAUTH 1.0 VS 2.0
There are major differences between OAuth 1.0 and 2.0 versions. Version 2.0 does not
support cryptography at the protocol level instead it uses TLS what makes version 2.0 more
vulnerable to all types of attack that TLS is vulnerable to. Another major difference is lack of
secure credentials set on each protected resource request in version 2.0. In version 1.0 both
token and client credentials are in use while in version 2.0 client credentials are no longer used
(Hammer E. , 2010).
2.6.8. SOAP PROTOCOL VULNERABILITIES
unique number that is used only once. OAuth includes nonce when generating a request signature in
order to ensure that only party that owns the shared secret can generate a valid hash and validate the
signature.
3
38
When we look at the backend of the Web service we find that SOAP as the compound
communication model protocol is highly vulnerable to many types of attack. This part of the
model must be extremely protected and security model should be revised against threats related
to integrity and confidentiality of the communication.
SOAP is vulnerable to several types of attack and these with the highest likelihood are:
the message can be spoofed with a Web service well-formed message that lacks valid security
claims to warrant communication
the message sent to Web service can be spoofed by an attacker in the way that the message does
not lose the consistency what causes that the service processes the request as valid and responds to
the client.
We see that SOAP implementations are highly vulnerable to major security threats and in
order to deliver secure point-to-point communication we need to ensure that confidentiality and
integrity are well secured.
Some of the security issues related to SOAP protocol can be resolved with XML encryption
and XML signatures and some can be resolved with different standardizations created to
securely represent security information inside the SOAP message (Bertino, Martino, Paci, &
Squicciarini, 2010).
2.6.9. RBAC MODEL STRENGTHS & VULNERABILITIES
Very common information security challenge is enforcement of security policies that tend to
protect organization against fraud. With Role-based security mechanisms it is possible to
enforce separation of duties (Ferraiolo & Kuhn, 1992). This means that not a single individual
is allowed to execute all transactions. As an example we can look at the bank payment system,
where payment transaction has to be initiated by a different individual than the one that
approves the transaction (Ferraiolo & Kuhn, 1992).
2.7. CONCLUSIONS
This chapter reviewed currently the most promising Identity and Access Management
models that federate identities and are scalable in the way that makes them suitable for large
cloud-based implementations. Next generation authentication models are not like their
predecessors a ready out-of-the-box products but are rather evolving frameworks that try to
39
follow the latest identity management trends, with federated identity and IDaaS models settled
as the core concepts.
The most important finding of this chapter is that the most of the federated identity
management, access control and authentication concepts are frameworks that try to align with
heterogeneous organizational infrastructures which slowly migrate into cloud computing.
RBAC and ABAC not only define distinguished access control models but like other
frameworks can be customized and be deployed together as one consistent access control
system.
Despite of new ways of authentication and identity management the traditional identity
repositories like directory do not change and they only expand domains which constitute
security boundaries for directories into the cloud services.
The major concerns are related to the cloud and its global scalability abilities that actually do
not guarantee sufficient data protection under different jurisdictions. Despite of cloud providers
warrants ensuring that data in the cloud they deliver will be safe many governments and major
market players do not trust the cloud computing and keep the data within their internal security
boundaries.
40
Figure 21 IDaaS implementation with iIdManagement and iADConnector (FIM, IAM and LDAP connector)
41
The iADConnector Service has been developed to simplify queries and reports on data that is
stored in the Active Directory and other LDAP repositories that are spread across the
organization and trusted parties. Using LDAP based queries for certain types of reports do not
efficiently perform as it is not optimal. Object filtering scenarios are limited and performance is
significantly impacted with increasing filter complexity. LDAP was designed to well-perform
for authentication and authorization therefore LDAP used for reporting and auditing can be
used but have an impact on the performance of directory based environment.
The iADConnector Service inventories objects from Active Directory and LDAP directories
into dedicated SQL database. Because iADConnector service acts as a Read-Only Domain
Controller for MS AD only change deltas of AD objects are being updated into the DB.
42
Memberships of several groups across forests and domains for review purposes.
Memberships of several groups across forests and domains combined with user attributes
for membership rules.
Active Directory group data for ownership and general maintenance purposes.
Active Directory group and user data for RBAC and ABAC mass transactions.
43
3.3. ARCHITECTURE
3.3.1. INTRODUCTION
The iIdManagement is using MS SQL server and its functionality benefits from MS SQL
query language and management tools that are delivered with the MS SQL product. This is
more development framework rather than implementation that will work in all IAM and FIM
scenarios. There is only one MS SQL server instance, which is hosting iIdManagement
database. It delivers meta-directory for the custom FIM implementation.
In iIdManagment digital identities are constructed based on automated or manual process
using Stored Procedures. Constructed digital identities are compound of other linked identities
(accounts) across various security boundaries via meta-directory.
The iIdManagement joins two account sources under one federated identity. The one
accounts store for iPortal is based on SQL database and the other for Enterprise Portal is a
meta-data from Enterprise Active Directory (SpyraConsulting.net AD forest).
iPortal and Enterprise Portal are two pages hosted on one MS IIS server in the cloud. Are
build using ASP.NET with DevDefined.OAuth .Net libraries. They authenticate user using
iPortal database, which is created for federated identity and Role-based security purposes.
The iADConnector is a Windows service built on top of the .Net Framework. The service
was designed to work in distributed, client-server or cloud-based environments; however the
service can run only on the MS Windows based machine.
The iADConnector synchronizes data from LDAP directories into dedicated SQL database.
ELEMENT
NUMBER
COMMENTS
Instances
Threads initialized
LDAP Connections
NO_CPU_CORE_PER_GC *
MAX_DC_POOL_THREADS
Several instances of the server can run simultaneously against one database to split data
processing per different security boundaries and to ensure that issues from one security
boundary will not affect inventorying performance of the other security boundary.
44
The iADConnector does not retrieve LDAP data changes deltas using multi-threading,
however it uses the multi-threading technique to retrieve and process the object attributes that
were changed in LDAP and parse them to the correct type and format required for DB. Objects
that were changed are just retrieved without any other information that the object
distinguishedName so the multi-threading can find the changed object and collect all the
attributes required for inventory.
The iADConnector establishes several LDAP connections per server to go around the LDAP
connection limitations that restrict number of simultaneous LDAP queries per LDAP
connection. The number of LDAP connections is calculated based number of open connections
using MS AD domain controller specific formula.
The iADConnector as a simple service does not use any external components except
.Net Framework. All internal components can be logically represented as inventory cycle steps
(see Figure 26 iADConnector inventory schema). This representation does match the service
flow, if we would use a different and more detailed granularity (e.g. using functions that
perform specific operations) because of the LDAP structure and LDAP objects relationship that
does not match the data structure of SQL databases. Interconnections between different LDAP
objects to be simplified for the DB require very specialized approach that transforms
hierarchical directory objects relationship into transactional database structure.
3.4. DATA
3.4.1. INTRODUCTION
The iIdManagement database is MS SQL database with couple dedicated Stored Procedures.
Because the existing system design before iIdManagement was based on MS technologies the
preferred solution had to suit the existing system. The iIdManagment is a framework that
benefits from identity stores that are located on the same MS SQL server instance. It joins
different identities from different identity stores under one federated identity and using ABAC
based operations against different identity stores enables or disables access to iPortal page.
The iPortal database is a simple account store for iPortal page. Registered iPortal accounts
with passwords hashes are stored in iPortal database. Because these accounts belong to a real
person that has more than one account in several systems, they are subjects for federated
identity management.
45
The iIdManagement is a heart of all identity related operations (complete tables and columns
description can be found in Appendix F).. Using Stored Procedures it provisions new digital
identities, which are then joined with accounts from iPortal and iADconnector. The identity
linking is performed in two steps. First we need to provision the global identity and then
dedicated Stored Procedures link different accounts. The iPortal account linking is very
simplified and cannot be automated, as the accounts store (iPortal.dbo.Accounts table see
Figure 24) does not provide enough information to match account information with identity
meta-data.
46
The iIdManagement delivers also access control functionality. The set of two tables
(see Figure 25) controls access to iPortal page with RBAC rules enforced through ABAC
(complete tables and columns description can be found in Appendix H). This part of
iIdManagement is also a development framework that can control access across different
interconnected systems.
The iPortal account store defines whether stored account can access the iPortal or not with
dedicated status attribute. iIdManagement manipulates with iPortal access using federated
identity and different properties of the digital identity that are stored across account stores.
47
3.4.2.2. iADConnector
The iADConnector maps two schemas the one from LDAP with custom SQL DB schema.
Because of the directory (mostly MS AD) specific representation of object properties the
service transposes LDAP native schema into data schema that can match transactional
database. E.g. MS AD uses additional dedicated attribute to store group memberships. This
attribute is part of the schema and this transformation is transparent for the end-user who sees
group members as a list of objects in user-friendly format. This exposition is using the
dedicated linking attribute, which actually keeps pairs of unique object indexes from directory
database. Transformations in such scenarios are very complex because the actual changes
(directory location, properties change) of the objects that are linked are not represented as a
membership link update but only an update specific to object itself. This might not be a
problem in small and medium enterprise (SME) as the member attribute of the group can be
parsed into delimited format or XML format and stored as any other attribute in the DB and be
overwritten with a new value. The problem arises when we deal with thousands of
memberships and in order to efficiently control and audit the security across different security
boundaries we need to keep membership data is a separate table. Because we do not know if
any of the group members on the list were changed we need to maintain event driven
functionality, which is implement for every object type and sends specific object update
information to the membership repository. Specific to directory objects interconnections
require inventory to store all objects from one security boundary in separate tables
differentiated only by object class. In MS AD the forest establish the security boundary for
interconnected domains.
48
49
The iADConnector advanced configuration and synchronization metadata are stored in two
tables under iADConnector database (see Figure 27). More details are provided in Appendix G.
3.5. CODE
3.5.1. INTRODUCTION
The code used to deliver working model is mostly C#, ASP.Net and MS SQL based. .Net
code is a mixture of ASP.Net with C# and C# with MS SQL snippets embedded for SQL
database inventory data control. MS SQL is used also on the database level through several
Stored Procedures that are delivered with the framework.
3.5.2. MODULES
3.5.2.1. iIdManagement
The Role-based security can be enforced only via Attribute-based security; this approach is
the most suitable for Meta-Directories where only identity properties are exposed outside the
security boundary. The iIdManagement is using two dedicated tables (see Figure 25) and
Stored Procedure to create a federated identity view with all interconnected accounts to create a
subset of identities that have or do not have access to resources based on attributes based ruleset. This approach requires automated accounts provisioning engine, which is not part of this
implementation.
3.5.2.2. iPortal with Enterprise Portal
The iPortal and Enterprise Portal are separate sub-projects from one ASP.Net based solution
that is delivered by DevDefined as OAuth implementation example. This example was
completely customized for evaluation purposes of this thesis.
The authorization and authentication flow are performed on one server across different
running web page instances. While Enterprise Portal is relying on MS Active Directory to
control access with Integarated Windows Authentication, the iPortal uses dedicated iPortal
database to store credentials. The iPortal database replaced account store delivered with OAuth
example. iPortal pages use set of OAuth 1.0 libraries also delivered by DevDefined. These
.Net Framework based libraries were also customized and precompiled to work with the model
developed for this thesis purposes. The examples are using latest OAuth 1.0 libraries
precompiled with .Net Framework 4.0.
3.5.2.3. iADConnector
The iADConnector service it is built of several different dedicated classes and uses all
benefits of .Net Framework 3.5. The inputs and outputs are always the same as iADConnector
consumes LDAP data as an input and through various transformations derives SQL DB data as
an output. Additionally the service uses XML configuration file, which stores the basic
information required to start the service and point it to the database instance. The major
configuration input, which includes encrypted credentials, comes from the database
(see Appendix G in Appendixes).
The engine connects to the directories and enumerates all objects and next stores them in a
dedicated database. The system that was built before iADConnector is based on
MS technologies and to make the service more consistent with existing meta-directory
solutions that were created before iADConnector. Service is using .Net Framework 3.5. The
51
.Net Framework version is especially important for the threads control so it is not
recommended to increment or decrement it without complete understanding of the code and all
internal components dependences.
52
3.5.4. INTERFACES
The iIdManagement platform does not expose any interfaces other than default interfaces
that are delivered with MS SQL server. Then the OAuth implementation communicates via
HTTP and there is no other communication between pages than through HTTP protocol. The
iADConnector code does not expose any interfaces. The set of custom libraries used in the
service are dedicated for the iADConnector and there are no plans to reuse them with other
code.
3.5.5. IDENTITY TYPES
3.5.5.1. iIdManagement
The database with dedicated Stored Procedures does not require any dedicated service
account. All identity related operations, which are automated are executed from database level
and do not require additional credentials. Because delivered iIdManagement database based
framework is going to be used only as a PoC dedicated security access control design is not
required.
3.5.5.2. iPortal with Enterprise Portal
The iPortal page has its own dedicated account store that keeps basic credentials information
required to authenticate and status of user account, whether account is active or inactive, what
determines access to iPortal.
Enterprise Portal is using MS Active Directory accounts and allows access to all
authenticated domain users using Integrated Windows authentication.
3.5.5.3. iADConnector
The service uses dedicated service account, which mainly needs access to the database
instance and service files. This account can be also used to access directory if no alternative
credentials are provided. The alternative directory credentials for service impersonation are
stored in a dedicated configuration database table. These are stored in an encrypted form and
are decrypted ad hoc when the service attempts to access the directory.
With default service credentials Windows Authentication is used to access directory,
however if there are alternative credentials provided for the directory the service performs the
LDAP bind operation using the alternative credentials.
53
3.7. INSTALLATION
3.7.1. IAAS
The IDaaS implementation requires IaaS platform with Microsoft Windows Server installed.
It requires pre-installed .Net Framework in version 3.5 and 4.0. To run fronted the
MS Visual Studio 2010 and MS IIS are required. The back-end will require MS SQL Server in
version 2005 and newer.
3.7.2. IIDMANAGEMENT
iIdManagement database framework does not require any specific installation. For this thesis
purposes the default database that can be created with Microsoft SQL Server Management
Studio wizard is sufficient. The only requirement is to recreate the default database schema
using script provided.
Installation steps:
*create dedicated SQL jobs to automate RBAC and ABAC data processing using stored
procedures
54
install the iADConnector service on the machine that has access (no blocked with firewalls) to the
DB instance
configure the iADConnector XML configuration file and specify the connection string for the DB
The NT Shell script can be used to install the service. This script is a part of the
iADConnector package.
There are two scenarios for post-installation service configuration adjustments:
service is running with credentials that are used to access directory; in this case default service
credentials have to be changed
service will use alternative credentials to access directories; in this case the only consideration is
whether default system credentials set by default for the service can access the service database
and if cannot the service required dedicated service account to run under it
3.7.5.2. iADConnector service configuration
service XML configuration file, which is located under service program file folder
dedicated database table that is selected based on the XML configuration file
When all tables are in place including configuration table, synchronization meta-data table
and inventory tables, the service needs some additional adjustments. The DB schema defined
for the inventory has to reflect the LDAP object classes and inventory types. This is done with
the service configuration table. The configuration example is delivered with the iADConnector
package (see Table 5 Advanced service configuration).
Alternative credentials for service impersonation are also stored in the configuration table.
55
*it is important from security reasons to provide alternative credentials as the last step of the
configuration, just before the service is started; credentials before are encrypted are stored in
plain-text format.
3.7.6. DEDICATED DATABASE
When the database is created without any specific schema defined the complete
iIdManagement and iADConnector databases structure can be created from the SQL scripts
provided. It is very important to create one set of inventory tables per either directory or forest
(only MS AD scenarios).
*any additional columns iADConnector for new LDAP attributes can be defined at this stage,
also columns that are not part of the LDAP schema can be added here if are required for
various administration or identity management purposes
3.9. SECURITY
The iPortal database does not stores password but only MD5 hashes for user passwords. This
will not provide sufficient security required for enterprise size implementations, however
hashed password allows users to authenticate against iPortal and does not expose passwords to
anyone who can view credentials stored in the database.
56
57
3.11. CONCLUSIONS
This HLD delivers a model with all major components that are required to build an enterprise
sized federated identity infrastructure with Role-based security. This chapter of the thesis
presented how the IDaaS cloud service can be implemented and how all integral components
are interconnected do deliver federated identity authentication functionality with Role-based
security. These components consist of FIM development framework named iIdManagement,
that is created using MS SQL server, which benefits from wide MS SQL database server builtin functionality. This component manages digital identities from two account repositories. One
account repository is created to control iPortal access and is logically located in a separate
cloud instance. The second account repository is a database inventory of directory data that is
located in a different logical cloud instance. Both database repositories are located on the same
MS SQL server instance what allows iIdManagement framework to control federated identity
what satisfies findings from Section 2.2.3. The directory connectors that are delivered with
iADConnector service give the possibility to retrieve subsets of identities across organizations.
This complex implementation gives a very powerful platform for RBAC via ABAC access
control what satisfies finding in Section 2.4.2. The front-end that is created in ASP.Net with
underlying OAuth 1.0 libraries simulates two separate portals that are located on two separate
cloud instances. Because this model is only created as a PoC for this thesis there are many
possible enhancements and security considerations if this framework meant to be rolled-out
into enterprise. Last two sections of this chapter are dedicated to these concerns related to
delivered PoC design.
58
59
4. CLOUD-BASED IMPLEMENTATION
4.1. INTRODUCTION
This chapter describes all details of cloud-based implementation, which was designed in
previous chapter of this thesis. The complete code including .Net libraries, NT Shell and SQL
scripts, and stored procedures created for this Proof of Concept are not presented here, although
all are listed here and referenced either to Appendixes or files from installation package. The
following sections cover all the implementation details that are important for the next,
Evaluation chapter.
Almost all parts of the implementation were scripted either using NT Shell or SQL. This
makes this prototype transferable to any other cloud instance. Because the back-end engine is a
development framework rather than a ready product it can be rebuilt on any other server and
used for testing and evaluation purposes. The front-end component is a .Net solution delivered
by DevDefined and is also very movable as does not require dedicated installation. The frontend iPortal and Enterprise Portal are published with MS IIS.
All further server adjustments and prototype specific configuration are described in the next
sections of this chapter.
60
61
Because the constructor declares token expiration date with DateTime object that not
necessarily has to be initiated with any date/time there is a small change implemented in
DevDefined.OAuth library, InMemoryTokenRepository.cs class:
public void ConsumeAccessToken(IOAuthContext accessContext)
{
AccessToken accessToken = GetAccessToken(accessContext);
if (accessToken.ExpiryDate != DateTime.MinValue && accessToken.ExpiryDate < Clock.Now)
{
throw new OAuthException(accessContext, OAuthProblems.TokenExpired, "Token has
expired");
}
}
62
The first part are two changes to the the Web.Config (see Table 4), one to change the
authentication method and the second to add the new database connection string:
<authentication mode="Forms">
<forms loginUrl="Login.aspx" cookieless="UseUri">
<!--<credentials passwordFormat="Clear">
<user name="john" password="password"/>
<user name="jane" password="password"/>
</credentials>-->
</forms>
</authentication>
<connectionStrings>
<add
name="iPortal"
connectionString="Persist
Security
Info=False;Integrated
Security=SSPI;database=iPortal;server=IP-0A74C61D\SQLEXPRESS;Connect Timeout=120" />
</connectionStrings>
The second part is to change the code that validates the credentials and this is done in
login.aspx.cs ASP.Net page code by adding new Authenticate method:
private bool Authenticate(string sUserName, string sPassword)
{
string sQuery = @"
SELECT COUNT(*)
FROM
Accounts
WHERE
userName = '{0}'
AND
passwordHASH = '{1}'
AND
isActive = 1
";
using(
SqlConnection
sqlConnection
=
new
SqlConnection(ConfigurationManager.ConnectionStrings["iPortal"].ConnectionString) )
{
sqlConnection.Open();
using (MD5 md5hash = MD5.Create())
{
using(SqlCommand sqlCommand = new SqlCommand(
String.Format(sQuery,
sUserName,
String.Join(String.Empty,
md5hash.ComputeHash(Encoding.UTF8.GetBytes(sPassword)).Select(cByte
=>
cByte.ToString("x2").ToUpper())) ),
sqlConnection) )
{
using ( SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())
{
sqlDataReader.Read();
if (Convert.ToInt16(sqlDataReader.GetValue(0)) == 1)
{
return true;
}
}
}
}
}
return false;
}
63
To publish the pages on a cloud instance to make them available in Internet there is couple
code
changes
required.
When
both
DevDefined.ExampleConsumerSite
and
DevDefined.ExampleProviderSite projects are published with MS IIS there are two additional
changes required.
The second one is also simple, however requires the project rebuilt. This change need to be
done in DevDefined.ExampleConsumerSite solution to OAuthPage.cs code file:
//string callBackUrl = "http://localhost:" + HttpContext.Current.Request.Url.Port + "/Callback.aspx";
string sCurrentPage = HttpContext.Current.Request.Url.AbsoluteUri;
string callBackUrl = sCurrentPage.Substring(0, sCurrentPage.LastIndexOf('/')) + "/Callback.aspx";
64
To extend the model to control access on the Resource Owner side with IWA the code has to
be
extended
on
both
sides,
iPortal
and
Enterprise
Portal
side.
On
the
The part of the code that is on the client site is from DevDefined.ExamplesConsumerSite in
ViewData.aspx.cs. The example came with a small code error, which can be fixed with the
following code that properly handles OAuthException. Also the communication channel from
OAuth 1.0 needs to be replaced with IWA authentication:
65
try
{
if (((IToken)Session[accessTokenString]) != null)
{
session.AccessToken = ((IToken)Session[accessTokenString])
ConsumerKey = "fake", Token = "fake" };
??
new
TokenBase
try
{
string response = session.Request()
.Get()
.ForUrl(Settings.Default.DataUrl)
.SignWithToken()
.ReadBody();
xmlFeed.DocumentContent = response;
}
catch (OAuthException oauthEx)
{
ErrorInfo.Text
=
String.Format("Access
was
denied
to
resource:<br/>{0}<br/><br/>", oauthEx.Message);
}
}
else
{
string
sIWAuthentication
=
String.Format("{0}/DataIWA.aspx",
Settings.Default.DataUrl.Substring(0, Settings.Default.DataUrl.LastIndexOf('/')));
using
(HttpWebResponse
webResponse
(HttpWebResponse)WebRequest.Create(sIWAuthentication).GetResponse())
{
xmlFeed.DocumentContent = webResponse.ReadToEnd();
}
}
}
catch (WebException webEx)
{
var response = (HttpWebResponse)webEx.Response;
if (response.StatusCode == HttpStatusCode.Forbidden)
{
ShowOAuthProblemDetails(response);
}
else
{
ShowStatusCodeDetails(response);
}
}
66
server. To access the pages from the server more beneficial is using MS Visual Studio 2010 so
the authentication flow can be tracked using VS Debugger.
67
Figure 32 Active Directory Users and Computers console provisioned domain structure
4.5. META-DIRECTORY
4.5.1. IIDMANAGEMENT
4.5.1.1. Database installation
iIdManagement database should be created on the same MS SQL server instance as other
meta-directory components. The default database configuration that is pre-defined when using
Microsoft SQL Server Management Studio wizard is sufficient to build a working framework.
Scripts folder iIdManagement\sql_scripts contains SQL scripts required to create default
tables definition. The tables were provisioned using NT Shell command on the SQL server:
FOR /R %i In (tbl_*.sql) DO SQLCMD -S IP-0A74C61D\SQLEXPRESS -d iADConnector -i %i
68
The successfully provisioned database should contain the following tables and columns:
Table Name
Identity
iLinking
iSource
iRule
iRuleDef
Column Name
pk_id
Surname
FirstName
MiddleName
Country
City
Description
fk_identityID
fk_iSourceID
fk_AccountID
fk_Account
pk_id
name
tableContext
description
ruleName
isActive
dtCreated
pk_id
fk_iRuleID
isExclusion
country
division
department
distingusishedName
dtCreated
All stored procedures required by the prototype can be found in Appendix I or in the package
folders with SQL scripts required for DB provisioning.
4.5.2. IADCONNECTOR
The service is a milestone for this thesis and successful FIM implementation with Role-based
access control relies on the properly build model with meta-directory framework.
4.5.2.1. Database installation
using
NT Shell
command
on
the
69
SQL
server:
sync_control
user
contact
group
computer
membership
Column Name
DNSDomain
KeyName
KeyValue
Description
dcDNS
invocationID
highestCommittedUSN
domainName
tableContext
dtSynced
pk_id
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
department
c
UAC_ACCOUNTDISABLE
pk_id
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
department
c
UAC_ACCOUNTDISABLE
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
description
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
department
location
description
operatingSystem
group_dn
member_dn
group_cn
member_cn
The xml file is using default format for .Net ConfigurationManager namespace. It uses
AppSettings and ConnectionStrings sections utilizing simple key/value configuration
convention.
appSettings
Key
configuration
interval
schedule
firstrun
Value
Configuration
1
22:00
0
Mandatory/Optional
Mandatory
Mandatory
Optional
Optional
70
Value
Persist Security Info=False;Integrated
Security=SSPI;database=iADConnector;server=IP0A74C61D\SQLEXPRESS;Connect Timeout=120
Mandatory/Optional
Mandatory
DNSDOMAIN
domain.net
domain.net
domain.net
domain.net
domain.net
domain.net
domain.net
domain.net
KEYNAME
ComputerEnumeration
ContactEnumeration
FspEnumeration
GroupEnumeration
MemberEnumeration
SecurityEnumeration
UserEnumeration
SyncControl
ComputerTable
ContactTable
FspTable
GroupTable
MembershipTable
SecurityTable
UserTable
NearSite
Default
domain.net
Password
Default
domain.net
User
KEYVALUE
1
1
1
1
1
-1
1
sync_control
computer
contact
fsp
group
membership
security
user
SITE_NAME
PW=nCSoT/ya8etDMKf1vDpXU
PaGdAtKBhX6uSec30T1mrb5RS
DIbwH9ooM
ID=aN4KEzh1yPxu8qL9UjP5cuv
zz/
MANDATORY/OPTIONAL
Optional
Optional
Optional
Optional
Optional
Optional
Optional
Mandatory
Optional
Optional
Optional
Optional
Optional
Optional
Optional
Optional
Optional
section where KeyName ends with *Enumeration enables/disables different types of enumeration;
value 1 states for enabled and works in intervals; value 0 states for enabled and works on
schedule; value -1 states for disabled enumeration
SyncControl KeyName column value specifies the location for synchronization meta-data
section where KeyName ends with *Table specifies the name of the table for specific enumeration
type
KeyName User and Password stores encrypted credentials for given domain
*Example configuration can be created using configuration.sql SQL script thats part of the
iADConnector package.
The service accounts should be properly permissioned over directory. There are MS AD
forest specific permissions which enable service to process deltas of changes and act as ReadOnly domain controller. These permissions can be set from CLI using following commands:
71
4.6. CONCLUSIONS
This chapter of the thesis covered the cloud-based implementation of all prototype
components. This implementation proves that the identity can be federated and controlled with
Role-based security via ABAC model (Section 2.4.2). Because it delivers very scalable FIM
framework that works across security boundaries it satisfies federated identity model described
in Section 2.2.3.
The delivered system authenticates the client and authorizes the resource access between
portals using OAuth 1.0 protocol (Section 2.3.2) or IWA (Section 2.3.1). The underlying
federated identity engine called iIdManagement recognizes identity for the account and based
on an ABAC match with the other account of this identity it decides, whether access can be
granted or should be denied. This is possible due to the underlying meta-directory that
normalize cross-account stores communication because of the SQL platform and framework
that is controlled with stored procedures. The iADConnector is responsible for account store
maintenance, which is inventoried from external directory source. It successfully handles
approximately 10k provisioned accounts what makes it suitable for enterprise implementations
what meets one of the thesis objectives. All of the above also show that the PoC
implementation meets all the functional requirements from High Level Design chapter.
72
5. EVALUATION
5.1. INTRODUCTION
The aim of this chapter is to test the model delivered with this thesis and to evaluate
technologies that this model use. Because the PoC covers wide scope of concepts related to
federated identity and IAM with Role-based security it actually addresses the most important
concerns related to security and authentication infrastructures. OAuth protocol is evaluated
together with IWA authentication. Tests will be carried out directly on the cloud instance and
also from the Internet to assess the two technologies and show how they scale across security
boundaries. Locally accessed portals represent access within single security boundary while
portals exposed as a cloud service belong to two different security boundaries. An evaluation
uses simple technical methods to clearly prove, which authentication and authorization methods
meet requirements related to security and federated identity concept.
5.2. METHODOLOGY
The PoC implementation and delivered framework give possibility to test different scenarios
where request it either approved and access granted to the resource or is not approved and
access is denied. Evaluation methods are grouped into simple categories that address the main
issues related to different technologies that are discussed in previous chapters:
The testing environment consists of two logical components front-end and back-end. The
front-end provides two links for two different authentication and authorization techniques
(see Figure 33). The object that is protected are Johns contacts. Clicking Click here button
for each of two selected technologies initializes authentication flows. Based on different initial
conditions access to the resource will be granted or denied. The only exception regarding initial
conditions is related to token expiration test, where access is withdrawn from the subjects
security entitlements.
73
Windows Integrated Authentication has its advantageous over other authentication methods
it actually gives access to resources that are in the same security boundary as the security
principal that claims access to these resources. Only successfully authenticated client, whether
it is a user or a computer can perform operations against the resource within Windows
Integrated Authentication environment. There are methods to enable security principal to claim
resource access from other than its own security boundary (here other Active Directory forest),
although this specific configuration of external trusts is normally made after enterprises legal
agreements so there is no risk that individual grants access over internal resources outside of
enterprises security boundary, which remains under Windows Integrated Authentication
infrastructure control.
The IWA test performed from within the development environment where only one security
boundary is available to authorize against the resource was successful (see Figure 34). The
same resource access attempt using IWA via portal opened from the cloud-based instance fails
(see Figure 35). In the first test Resource Owner and Identity Provider (iPortal) are sharing one
security boundary: SpyraConsulting.net forest. In the second test access to the resource is
74
denied because the Identity Provider is still in the AD forest boundary, while Resource Owner
is accessing IP from Internet.
75
MS Active Directory security access token - shorter SAT, is created when user logs in into
the system and the token is valid for the time that the user is logged (Price, Price, &
Fenstermacher, 2008). If the user loses security permissions this is not automatically reflected
on
the
security
token.
MS AD
account
can
then
perform
actions
on
Windows Integrated Authentication enabled infrastructure and it also keeps access to resources
as the security identifier (objectSid) of the group that gives access to the resource is present in
the SAT which is tightly dependent on the users Windows session.
The object - protected resource access is secured with dedicated MS AD SecureDataAccess
security group. The Windows account that is used to access the resource is a member of this
group. Using IWA authentication the Kerberos token is checked for this security entitlement
and if the group is on the security token groups list user is granted the resource access (see
Figure 34).
Figure 36 IWA local test with Kerberos security token; user is a member of security group access granted
When we remove the user from the security group the access should be withdrawn, however
the default Kerberos ticket lifetime in MS AD is 10 hours (Walla, 2000), so the ticket remains
unchanged unless the lifetime elapsed or user logged off from the system (Price, Price, &
Fenstermacher, 2008).
76
Figure 37 IWA local test Resource Owner spyra removed from the security group
Even when the user was removed from the group the Kerberos ticket based authorization still
grants access to the resource and receives the same data set as in the previous local test
(see Figure 34). While debugging the code during Kerberos authorization (see Figure 38) it
shows that the group was not removed from the ticket and access is still valid.
Figure 38 IWA local test Kerberos ticket entitlements based on security groups memberships access granted
The access to the resource was withdrawn when the user was logged of from the Windows
session and when to SAT was deleted from memory (Price, Price, & Fenstermacher, 2008).
5.3.2. OAUTH
5.3.2.1. Scalability across security boundaries
OAuth protocol was created to control access to resources across different security
boundaries (Hammer E. , 2010). Its advantage over Integrated Windows authentication is its
77
scalability. Because the token can be securely send using HTTP the authentication system will
be able to control resource access even if the ticket need to be issued outside the domain of
Identity Provider (in our model MS AD forest). In our example the OAuth protocol to
authenticate Resource Owner uses username and password set. Because these credentials are
only provided on the IP side (iPortal API) the further actions required to obtain resource access
are secured.
The both tests, using local development environment and cloud-based service, resulted in
granted access to the resource. To access the object the Resource Owner is redirected to iPortal
to provide credentials: username john, password napier123 (see Figure 39).
Figure 39 OAuth cloud-based and local tests; Step1 - successfully redirected to IP for authentication
When RO is successfully authenticated with IP iPortal displays access control page so the
RO can decide whether issue the access token for the resource or decline the request
(see Figure 40).
78
Figure 40 OAuth cloud-based and local tests; Step2 access control page RO successfully authenticated
When access is granted by RO the security access token is released and client
(Enterprise Portal) receives protected resource data (see Figure 41).
The OAuth protocol issues security access token per access request. This token has its
security context relevant to resource and RO. Unlike with IWA the security token has lifetime
property specific to this security context. This value can vary and because OAuth is not related
79
to any particular product the developer who implements OAuth infrastructure can decide how
to handle tokens lifetime. When IP issues the access token the resource can be access as long as
the ticket is valid.
Both resource access token leases timed out in one minute and when resource access was
claimed the access was denied.
Figure 42 OAuth cloud-based and local tests; token expired access denied
OAuth
passed
IWA
passed
Comments
none
passed
failed
none
passed
failed
boundary. Having identity independent from one authentication system we can control what the
identity is entitled to do across different platforms. Because Role-based security corresponds to
organization structure it does not easy scale outside the organization with internal
organizational rules. RBAC systems need a communication path to exchange identity role
information. This is where ABAC implementation can be used. Exposed part of internal
structure via ABAC from other organization can be used to enforce RBAC rules. Enough that
properly provisioned identity property corresponds to the organizational rule and the ABAC
engine can use this property to control access of the foreign identity.
To test this part of the model used OAuth and enforce RBAC control on Resource Owner.
The internal iPortal account store keeps RO credentials. iPortal accounts are linked using
iIdManagement (see Section 3.4.2.1) view of federated identity. This view was created using
stored procedures. Because iPortal accounts cannot provide sufficient information to uniquely
link identities with other account stores this process needs to be performed manually using
following commands:
--Register identites
EXEC iIdManagement.dbo.RegisterIDentity @Surname = 'Napier', @FirstName = 'John', @description='Scientist'
--Register iPortal accounts
EXEC dbo.LinkIdentityFromiPortal @Surname='Napier', @FirstName='John', @userName='john'
Because newly created identity view for John Napier has enough properties to match the
linking rule (see stored procedure in Appendix I) for iADConnector account store join the
existing identity view can be automatically joined with respective account from different
security boundary under one federated identity. The current view of the identity can be created
with custom SQL query:
81
SELECT
FROM
ID.FirstName as FI_FirstName,
ID.Surname as FI_Surname,
ID.[Description] as FI_Details,
ACC.userName as LO_userName,
ACC.[status] as LO_accountStatus,
USR.sAMAccountName as DS_userName,
ISNULL(USR.department,'') as DS_department,
CONVERT(varchar(20), GETDATE(), 120) as view_date
iIdManagement.dbo.iIdentity ID
JOIN
iIdManagement.dbo.iLinking LNK
ON
ID.pk_id = LNK.fk_iIdentityID
JOIN
iIdManagement.dbo.iLinking BLNK
ON
LNK.fk_iIdentityID = BLNK.fk_iIdentityID
JOIN
iPortal.dbo.Accounts ACC
ON
ACC.userName = LNK.fk_Account
JOIN
iADConnector.dbo.[user] USR
ON
USR.pk_id = BLNK.fk_AccountID
The return information about the federated identity will be compound of different properties
from inter-connected accounts that belong to different security boundaries.
We see that only John Napier has active iPortal account, what is indicated with
LO_accountStatus column. This status is controlled with stored procedure (see Appendix I) and
iRule sets:
SELECT
RBAC.ruleName,
ISNULL(RBAC_DEF.country,'') as country,
ISNULL(RBAC_DEF.division, '') as division,
ISNULL(RBAC_DEF.department, '') as department,
CONVERT(varchar(20), RBAC_DEF.dtCreated, 120) as whenCreated
FROM
iIdManagement.dbo.iRule RBAC
JOIN
iIdManagement.dbo.iRuleDef RBAC_DEF
ON
RBAC.pk_id = RBAC_DEF.fk_iRuleID
82
The only entitled department over Resource is HR, and logon attempts with any other
accounts from other than HR departments return access denied message.
Figure 43 ABAC enforces RBAC rules and bill account cannot control the resource
When we add another department (see Table 9) to the rule we will see that ABAC engine
based on exposed attributes from one account repository activates iPortal accounts (see Table
10).
Table 10 ABAC engine enforced RBAC rule based on new department in the rule scope
83
REsult
passed
Comments
none
passed
none
passed
none
5.5. CONCLUSIONS
To make step with RBAC beyond federated identity there might be a need to introduce
public roles that are independent from an organization structure in the meaning that roles are
not native to the organization, however were implemented into the organization to support
model with unified roles that can go beyond organizational structure. Organizations from
various reasons mostly because of security concerns, do not want to expose internal structure to
either public or other organizations. These unified cross-federation roles might help to build
systems that utilize unified RBAC roles to grant access to resources based to group of identities
distinguished by role, which was introduced as a part of an internal RBAC system design.
84
To go further with this idea RBAC design can support cross-federation unified roles based on
attributes exposed on different identities via ABAC model implementation, where the ABAC
model based on identity provisioning corresponds to underlying organizational RBAC design.
E.g. specific set of identities from two organizations can be exposed from directories based on
the directory location and then matched to the unified roles using ABAC model where
identities with its attributes were provisioned to reflect organizational RBAC design.
85
7. CONCLUSIONS
7.1. OVERALL CONCLUSIONS
This thesis challenged the latest and the most important aspects of secure digital identity
authentication and authorization in era of cloud computing. The Research & Literature Review
section is fundamental for all further sections as it highlights what are the main components of
successful framework implementation that will federate the identity in the cloud under Rolebased security rules that consolidate with OAuth model. The delivered PoC satisfies IDaaS
cloud service requirements where effectively used directory as an enterprise identity store.
This first part of the thesis (Section 2.6) also carries out the critical review of the cloud
computing concept with implications for personal data protection under different governmental
jurisdictions. This highlights the conflict between benefits that come with cloud technology
itself and international law that tries to protect personal data (Section 2.6.1). This part uncovers
the weaknesses of the cloud computing and highlights what is the bottleneck of this technology
as for enterprises who care about reputation and customers trust personal data that can not be
securely held is not an option.
To prove findings from the first chapter custom IDaaS framework was designed that exposes
web-based interfaces for OAuth authentication required to evaluate underlying federated
identity processing including RBAC operations. To implement Role-based security
heterogeneous model was required to expose internal organizational roles outside to deliver
federated identity view what aligns with findings from Section 2.2.1, Section 2.2.3 and Section
2.4.2. The Integrated Windows authentication as a part of the design was selected to provide
backward compatibly with traditional authentication techniques. Before the design decisions
were made regarding IWA selection the first chapter (Section 2.3) helped to thoroughly analyse
constrains that addressed by next generation authentication infrastructures. Both Cloud-based
Implementation and Evaluation sections are compound and interfere together to deliver clear
findings and strictly technical results. These sections proves that the federated identity can be
effectively delivered as a complex enterprise framework which requires additional
customization to support Role-based security and enterprise directories. The OAuth as another
framework proved to be the suitable for cloud based implementations and perfectly matched
the underlying model as both resulted in successful evaluation of selected technologies.
86
The created model managed to authenticate and authorize identity with OAuth using
federated identity with Role-base security delivered as IDaaS cloud based solution.
interfaces
for
OAuth
2.0
and
this
is
the
next
technology
next
to
Windows Azure Active Directory that is worth to evaluate with enterprise size implementation.
The delivered framework for federated identity management with Role-based security, which
supports several identity sources including LDAP directories is one of my personal
achievements and currently started working on complete framework that can be customized for
RBAC and ABAC models. There is many serious market players that deliver similar products
to end users, however the model delivered is not a ready product, it is a development
framework, which with several enhancements can be successfully deployed for SME sized
customers. This framework can be very attractive for LE sector, however the business model
that comes with development framework not often suits LE sized customers.
The concept that arises while working with thesis is that all RBAC and ABAC transactions
for security reasons can be hashed with native SQL functions that can deliver MD5 hashing.
This with a good overall design can be used to create a well-secured product with enhanced
internal integrity (see Section 3.10.2).
7.3. ISSUES
During the implementation phase many problems occurred with OAuth model examples
(see Appendix B). Because complete OAuth implementation of the client and the server side
requires OAuth libraries that are not part of the .Net Framework the model required the
complete set of libraries to be either created from scratch or downloaded from other developers
on open license terms. Many examples delivered with more generic or very examples specific
libraries did not work or did not meet the model requirements. The most suitable for the
prototype set of OAuth libraries and examples was delivered by Erran Hammer, as a
DevDefined source code.
87
Recently several important events took place that are fundamental for the aims and
objectives of this thesis. This thesis responded to those changes as accurate as possible. This
aligns with the subject statement and proves that OAuth (see Appendix B) is a next generation
authentication technology. The most important fact was that one of the leading OAuth
founders and authors Eran Hammer at the 26th of July 2012 have published information that he
is leaving the project from IETF because of personal disappointment related to next release of
OAuth 2.0 that supposed to replace OAuth 1.0 and provide more complete model to the enduser. As per Erans statement OAuth 2.0 is much more complex than is predecessor although
was stripped from some security features that made the default implementation of OAuth 2.0
not well-secured (see Section 2.6.7) and not suitable for large enterprise anymore (Hammer E. ,
2010). This was one of the factors that caused changes to the further design and implementation
sections where instead of OAuth 2.0 libraries the previous version OAuth 1.0 was used.
The next fact is that when the PoC was created for this dissertation there was no official .Net
release of libraries for OAuth. At the 1st of August 2012, Vittorrio Bertocci from Microsoft
published information about official release of Windows Azure Authentication Library that
consists of several authentication interfaces including OAuth 2.0 authentication.
88
rigorous evaluation model was redesigning the prototype many types till it was mature enough
to satisfy the aims and objectives of this thesis.
To create a working cloud-based framework I used all the skills that I have gained during my
technical studies and years of professional work with directories. Because of the study field I
selected for my master studies I was able to look at this thesis from a different perspective. Not
only a technical one but also from the legal and risk perspective. The selected course gave me a
wider and better view on modern systems and problems that are behind IT in the 21st century.
The thesis from other author, Edinburgh Napier University student, were very relevant to the
subject of this thesis (Fernandez Sepulveda, 2008). He successfully compared different
authentication methods and delivered a good technical background for specific FIM
implementation. His work gave me an overview of what should be written about new
authentication techniques and federated identity. Since Fernandezs thesis many things have
changed, including OAuth which completely changed the view on authentication and
authorization systems.
There is much more I wanted to write here about what is related to information security but I
could not find the right place for it in the context and there was no time to go far from the
initial aims and objectives defined. I hope to have a chance in the future to write about the
latest method of making secure codes called Quantum Key Distribution (QKD) or about the Iris
scanning security vulnerability which allows unauthorized person to easily spoof the identity.
89
BIBLIOGRAPHY
Walla, M. (2000, May). Kerberos Explained. Windows 2000 Advantege , p. 1.
Windley, P. J. (2005). Digital Identity. Sebastopol, USA: O'Reilly Media.
Andersen, E. (2008, January). The X.500 Directory Standard: A Key Component of Identiy Management.
Telektronikk .
Arkills, B. (2003). LDAP Directories Explained: An Introduction and Analysis. Boston, MA, USA: Addison
Wesley.
Buchanan, W. (2010, March 14). Advanced Security and Network Forensics. Retrieved August 10, 2012
from Bill's Home Page: http://buchananweb.co.uk/unit06.pdf
Bertino, E., Martino, L., Paci, F., & Squicciarini, A. (2010). Security for Web Services and ServiceOriented Architectures. Heidelberg: Springer.
Bertocci, V. (2011). Programming Windows Identity Foundation. Redmond, Washington: Microsoft Press.
BlackBridge. (n.d.). BlackBridge. Retrieved 08 1, 2012 from Cloud Security -Enable Security and SSO in
the Cloud: http://www.blackbridge.it/radiant/cloudsecurity.html
Boeynaems, K. (2010, January 21). Pass-the-hash attacks: Tools and Mitigation. Retrieved August 4,
2012 from SANS: http://www.sans.org/reading_room/whitepapers/testing/pass-the-hash-attacks-toolsmitigation_33283
Deuby, S. (2011, March 9). Ease Cloud Security Concerns with Federated Identity. WindowsITPro , pp. 13.
De Clercq, J. (2004). Windows Server 2003 Security Infrastructures. Burlington, USA: Digital Press.
Desai, J., & Johnson, A. (2012, July 28). The truth about cloud security. (M. Benett, Interviewer)
http://www.on24.com.
Fernandez Sepulveda, A. J. (2008). Evaluation of Digital Identity using Windows CardSpace. Napier
University, School of Computing. Edinburgh: Napier University.
Ferraiolo, D. F., & Kuhn, R. D. (1992, Oct 13-16). Role-Based Access Controls. Gaithersburg, USA:
National Institute of Standards and Technology.
Information Commissioner's Office. (2010). Guide to data protection. Retrieved Aug 18, 2012 from ICO:
http://www.ico.gov.uk/for_organisations/data_protection/~/media/documents/library/Data_Protection/Pract
ical_application/THE_GUIDE_TO_DATA_PROTECTION.ashx
Hammer, E. E., Recordon, D., & Hardt, D. (2012, March 8). The OAuth 2.0 Authorization Protocol.
Retrieved July 20, 2012 from IETF Tools: http://tools.ietf.org/html/rfc5849
Hammer, E. (2010, May 15). OAuth. Retrieved July 21, 2012 from hueniverse:
http://hueniverse.com/oauth/
Lothian Buses. (2012, March 4). Term & Conditions. Edinburgh, United Kingdom: Lothian Buses.
Maples, W. (2008, August 2008). Active Directory database file NTDS.DIT. Retrieved July 14, 2012 from
WindowsNetworking.com:
http://www.windowsnetworking.com/kbase/windowstips/windows2000/admintips/activedirectory/activedire
ctorydatabasefilentds.dit.html
Mather, T., Kumaraswamy, S., & Latif, S. (2009). Cloud Security and Privacy. (M. Loukides, Ed.)
Sebastopol, USA: O'Reilly.
OConnor, A. C., & Loomis, R. J. (2010, December). 2010 Economic Analysis of Role-Based Access
Control. Gaithersburg,, USA: National Institute of Standards and Technology.
Pohlman, M. (2003). LDAP Metadirectory Provisioning Methodology. Lincoln, United States of America:
iUniverse, Inc.
Price, J. A., Price, B., & Fenstermacher, S. (2008). Mastering Active Directory for Windows Server 2008.
Indianapolis, Indiana, USA: Wiley Publishing, Inc.
Sandhu, R. S., Coyne, E. J., Feinstein, H. L., & Youman, C. E. (1996). Role-Based Access Control
Models. IEEE Computer , 29 (2), 38-47.
Sean, D. (2012, May 27). Microsoft Active Directory In The Cloud: Windows Azure Active Directory Is
Expanding Its Capabilities. Retrieved July 10, 2012 from Windows IT Pro:
http://www.windowsitpro.com/article/active-directory/microsoft-active-directory-cloud-windows-azureactive-directory-143222
Sosinsky, B. (2011). Cloud Computing Bible. Indianapolis, Indiana, USA: Wiley Publishing, Inc.
II
APPENDIXES
Appendix A
SUPERVISION
LITERATURE REVIEW:
DOCUMENT CORRECTIONS:
TECHNICAL CONSULTATIONS:
OAuth
Federated Identity
Cloud-based services
OTHER ASSISTANCE:
Appendix B
DIARY
Having self-compiled libraries simplified all further debugging required to make the example
running.
Decided to test other set of complete OAuth libraries freely available in the Internet. Tony
Williams DOAP libraries did not compile due to MS Visual Studio conflicts.
Andrew Arnott delivers another examples with DotNetOpenAuth project. The advantage
over the previously tried server side libraries is that it supports the latest OAuth 2.0 version.
When started the project found that project was configured to use Virtual Directories and was
failing. After several tries managed to find the source of the issue and modify all project files to
load the solution with MS Visual Studio 2010, however loaded solution components did not
compile. Reviewed all the dependences of the project and managed to configure the IIS server
to work with DotNetOpenAuth solution. OAuth client example works without problems,
although server side example does not work and returns no errors.
Reconfigured OAuthAuthorizationServer code to use local instance of SQL server. Managed
to run the code with Goolge as an Identity Provider, however fails when try to use the Identity
Provider service delivered with an example.
Implementation of working example brings a lot of frustration because of the bugs that are in
the code that is officially available. Another frustrating factor is that Erran Hammer, one of the
founders of OAuth specification at the 26th of July 2012 has left IETF and the OAuth 2.0
project due to specification disappointment. He has listed serious functionality and security
concerns related with OAuth 2.0 release here: http://hueniverse.com/2012/07/oauth-2-0-andthe-road-to-hell/.
After reviewing Errans publication realized that he actually spotted very important points
that are subjects to serious security concerns. To actually benefit from all best features of
OAuth decided to try once again implementing DevDefined OAuth 1.0 libraries from Alex
Henderson. It took me one day to recompile the libraries and debug it with an example
delivered for these libraries. Managed to solve the problem with token has expired error by
modifying library. The token validation component was testing token expiry data against
current date. In case if the token object was initiated without expiry date constructor was
defining the datetime variable with minimal value allowed being set under datetime variable.
Added additional testing criteria where check if token expiry date is not equal with minimal
allowed datetime value.
C
Having two working models one from Andrew Arnott and one from Alex Henderson could
select the best suitable one for the PoC that want to deliver.
Appendix C
PROFESSIONAL RESEARCH
To find out the current trends in IT and recognize the demand of having OAuth like
authentication that is used in cloud computing based implementation with Role-based security
the several discussions were carried out.
Gregory Spyra
ZH
Ask away
Christopher Westpoint
NY
From my perspective Im interested in how security is handled to cloud-based services and what options they have as well as
how they are technically handled.
Looking forward to continue this conversation.
Ask away
Christopher Westpoint
NY
Essentially Microsoft is extending AD into the cloud (nothing new, been extending AD into the DMZ for years) but in this
instance they handle the shadow accounts with federation principles (tying the objects together via a token secured by a
selected authentication mechanism, most likely Kerberos auth). Still trying to understand how it ties in with other Relying
Parties but interesting none-the-less.
A great question for your thesis -- What should/has to be done in order to call a cloud solution secure and how does one
manage privacy concerns (you will have a bunch of cloud engineers managing your data - whats to stop them from
using/reading it? Altruism? Legal contract?)
Federated Identity is the next big thing ;-)
Christopher Westpoint
NY
I think enterprise AD transition into cloud should be only partial as long as all regulations regarding cloud data are not
clear, and as long as next generation authentication methods are still fresh and mostly having more academic than
enterprise character.
I know quite a few AD bugs and Im bloody scarred when I imagine that I put our AD into public network area.
Do you know what are Azure AD security features that:
1. are implemented at the network level in order to restrict IP pool that can access the instance?
2.
are implemented at most of the system layers that protect against DoS or DDoS attack?
3.
Is there any set of recommendations regarding AD structure/configuration that will be implemented into the cloud
(many AD vulnerabilities now have a very low risk due to internal network facing, what when facing public).
Regarding your previous email, we plan to go into Federated Identity and would be nice to be ready for the cloud but
internally we still dont have Federated Identity model. We have so many different systems and even if they query AD to
validate user information, it often uses home-grown authentication model that has nothing to do with secure
authentication methods we want to use in the cloud. E.g. several times someone came to me telling that the naming
convention doesnt match their system as they read user CN and check the password stored locally in some custom
application server DB.
1.
If I would go into the FIM I say lets go but we need to centralize authentication to have the homogeneous
authentication infrastructure.
2.
3.
Would you like to get rid of AD at some point as SAML doesnt actually require any directory or did you mean that you
would rather use SAML to replace Windows Integrated Authentication model?
Thanks J
Greg
Gregory Spyra
ZH
2.
Doubt there is anything to stop a DDoS attack. If you think about it, there is nothing to stop it from internal AD.
There are multiple (easy) ways to take AD out. 1) write a script that adds users to over 500+ groups blowing out the token.
The DC wont log you on. MS fix was dont add people to that many groups J Second, overload the DNS servers - no SRV
record access no DC. Now Internet Providers probably have internal or 3rd party ways to stop this but not aware of the
details of how they work. Probably some type of service looking for a specific pattern (maybe like x number of requests
from host y within time z).
3.
Great question.
This is still in its infancy, but believe they assume security would be handled/maintained by the STS. Remember you get
access to the AAD via a token (not interactive password/etc). Someone would have to intercept the token, be able to open
it, expand the assertions, make a change, sign it (correctly), put it back in the token and then send it back -- all in order to
gain access. The fact that the person is not handling the authentication (by inputting a known identity value - such as
password) makes the request/process a *bit* more secure.
Assertions are the future in my book. It gives you centralized policy and allows flexibility of fine-grained access.
Another question I wonder about is, lets say we federate with a partner or other B2B communication. When they receive
our token they use the assertions to evaluate claims-aware access. What is someone started collecting the assertions from
the token to develop a profile of the source company. As a federated partner I can ask for attributes which may not be
sensitive, but may allow me to derive information -- or perhaps sell to others.
Since information is becoming the valuable commodity and since it is in essence abstract (though has a physical instance
component) - how do you protect it? Especially when it can be duplicated granting both parties involved with a copy.
I look at the Movie industry as an example. Once a movie is distributed from the Distributor there is absolutely no way they
can prevent that distribution from getting out of their channels. So for example there are movies where US rules state must
be banned (See Faces of Death) -- yet due to the fact that information is duplicated I can easily get this within the US
(bypassing the laws).
Laws have to be updated to meet the changes that digital information introduces, but it has to be fair and respect privacy.
For example, the US shouldnt be able to tell me what I am able to see or not see. Thats censorship.
We have to be careful what information we put out there about ourselves because no we have the tools to cobble and
correlate random bits into a bigger picture, perhaps providing information we consciously wouldnt allow to be used as a
whole, but obliviously to the information we give when we sign-up for social media. More is going on behind the scenes
than the public is privy too.
Christopher Westpoint
NY
Thats why I refuse to go on social sites (Im not on facebook, twitter, instagram, etc)
Spyra Gregory (INTERNAL DEP. NO) [18:02]:
I would say we stuck with Windows Integrated Authentication models for enterprises
Westpoint Christopher (INTERNAL DEP. NO) [18:02]:
yeah, thats the best - but for enterrpise we have to break authN from authZ
Spyra Gregory (INTERNAL DEP. NO) [18:02]:
because before we authenticate there are some pre-requisites we have to meet
yes
Westpoint Christopher (INTERNAL DEP. NO) [18:03]:
access policy should be centralized and customized to the scenario
Spyra Gregory (INTERNAL DEP. NO) [18:03]:
I was actually thinking about what you're saying for the last couple days
Westpoint Christopher (INTERNAL DEP. NO) [18:03]:
for example, who I am (Chris Westpoint) should be separate to what I have access to
and what I have access to should be determined by what I am accessing bringing in other variables such as sensitivity, time,
location, etc
(If chris is NOT in New York, and its between the hours of 8-5pm EST do NOT allow access)
Or - if I access my files I only have to provide password level security - but if I want to access HR data for IDM processes I
have to perform dual-factor auth
Today its up to each app owner to develop this - when it should be defined at the enterprise level
Spyra Gregory (INTERNAL DEP. NO) [18:05]:
this is the global problem, applications derive your permissions based on what you know rather than who you are
Westpoint Christopher (INTERNAL DEP. NO) [18:05]:
yup! :D
Spyra Gregory (INTERNAL DEP. NO) [18:06]:
and have no centralized identity
Westpoint Christopher (INTERNAL DEP. NO) [18:06]:
When I was at the Directory Experts Conference (DEC) in California in 2010 thats what I asked the 'experts'
Spyra Gregory (INTERNAL DEP. NO) [18:06]:
what did they answer
?
Westpoint Christopher (INTERNAL DEP. NO) [18:06]:
How do I handle authroization. And no one had a decent answer
MSFT has something custom but they dont believe in it enough to release to the public. Spoke to the Ops friends at MS and
they say its bloated and it sucks :)
Spoke to David Mowers (ex-MSFT) who was creating a new authorization type model
but when I picked his brain he was just using specific unused attributes in the PAC to convey access information
Again it works, but tightly integrated with MS implementation of Kerberos
AuthZ model has to be agnostic since not everyone in the world uses windows
Thats when I knew it was a valid problem and would need discussion/investigation/research to fix
Spyra Gregory (INTERNAL DEP. NO) [18:09]:
the problem with beloved Kerberos is that the SAT doesn't expire and is valid during whole user session.
another problem is that there is no direct way of rights delegation and in order to give access over resourced to the user
you need to actually add the user to the group
Westpoint Christopher (INTERNAL DEP. NO) [18:10]:
Yes, and as we know with TPA even when revoked you cannot KILL the ticket
Spyra Gregory (INTERNAL DEP. NO) [18:10]:
exactly
Westpoint Christopher (INTERNAL DEP. NO) [18:10]:
yup
I fully agree
Westpoint Christopher (INTERNAL DEP. NO) [18:16]:
thats why I left... I just didnt want to be the MS IDM guy
Spyra Gregory (INTERNAL DEP. NO) [18:16]:
:D
Westpoint Christopher (INTERNAL DEP. NO) [18:16]:
I wanted to be THE IDM guy - agnostic to product
Spyra Gregory (INTERNAL DEP. NO) [18:16]:
haha
Westpoint Christopher (INTERNAL DEP. NO) [18:18]:
My goal here is to make the best IDM solution on the street
to the point that the other banks follow what we do
I know the directory/IDM guys at GS, Morgan, Chase, and Citi
they dont have anything on us ;)
Spyra Gregory (INTERNAL DEP. NO) [18:20]:
Would be cool. First need EID guys to actually empower the meta-directory they build .. There is a couple small gaps to fill
in.
Trust me, oAuth is suitable for LE and it can align with RBAC/ABAC model and even beyond it.
you have 3 actors in oAuth
you have a client, resource owner, SP
the tricky part is that client asks SP on behalf of resource owner to get access to the resource
normally in other authentication scenarios client is either added to the SP and permissioned over the resource or it acts as
a resource owner
the second one is mostly dangerous as this is where many implementations accept username/password exchange with the
client
oAuth solves that in a magic way
Westpoint Christopher (INTERNAL DEP. NO) [18:24]:
agreed on the gaps
need to make the product easily extensible
Spyra Gregory (INTERNAL DEP. NO) [18:24]:
client contacts SP on resource owner behalf then owner needs to put a username/password but on the SP site what's effect
of client redirection.
Westpoint Christopher (INTERNAL DEP. NO) [18:24]:
adding the cs attributes is a complete chore
Spyra Gregory (INTERNAL DEP. NO) [18:25]:
resource owner provides u/p securely and then the magic happens..
Westpoint Christopher (INTERNAL DEP. NO) [18:25]:
SP = Service Provider
Spyra Gregory (INTERNAL DEP. NO) [18:25]:
:D
Westpoint Christopher (INTERNAL DEP. NO) [18:25]:
?
Spyra Gregory (INTERNAL DEP. NO) [18:25]:
yep
Westpoint Christopher (INTERNAL DEP. NO) [18:25]:
Hell, Ill have questions for you!
Spyra Gregory (INTERNAL DEP. NO) [18:25]:
I love this.. know other auth models and am inloved in this one
yes
Westpoint Christopher (INTERNAL DEP. NO) [18:38]:
ok. perfect
Who developed oAuth? (major contributors?)
Spyra Gregory (INTERNAL DEP. NO) [18:38]:
but the page will be ready when I finish designing supporting DB structures
Westpoint Christopher (INTERNAL DEP. NO) [18:38]:
individuals or vendors?
Spyra Gregory (INTERNAL DEP. NO) [18:39]:
Individuals
Appendix D
GANTT CHART
Appendix E
SPECIFICATION
Appendix F
Table Name
Identity
Table Description
FIM implementation component part;
Stores basic information required to
identify federated identity; All other
identity properties are part of the abstract
federated identity view and are available
via iLinking custom SQL joins;
Column Name
pk_id
Surname
FirstName
MiddleName
Country
City
Description
iLinking
fk_identityID
fk_iSourceID
fk_AccountID
fk_Account
iSource
pk_id
name
tableContext
description
iRule
ruleName
isActive
dtCreated
iRuleDef
pk_id
fk_iRuleID
isExclusion
country
division
department
Column Description
Primary key, used to uniquely
identify the identity within
database context;
Automatically propagated;
Identity surname; Potentially
can be filled automatically
when FId view is defined;
Identity first name; Potentially
can be filled automatically
when FId view is defined;
Identity middle name;
Potentially can be filled
automatically when FId view is
defined;
Identity country; Potentially
can be filled automatically
when FId view is defined;
Identity city; Potentially can be
filled automatically when FId
view is defined;
Identity description; Potentially
can be filled automatically
when FId view is defined;
Foreign key to Identity table;
Foreign key to iSource table;
Foreign numeric key to any
account store defined with
iSource;
Foreign free text key to any
account store defined with
iSource;
Primary key, used to uniquely
identify the identity within
database context;
Automatically propagated;
Unique name of the account
store;
Account store table location
with full database context path;
Random information relevant to
registered account store;
Unique name of the new
filtering rule; Used to
distinguished access control
operations specified for
different rules; Anchored in
Stored Procedures;
Specifies, wheter the rule is
active;
Information about data/time
when the rule was created;
Automatically propagated;
Used for auditing purposes;
Primary key, used to uniquely
identify the identity within
database context;
Automatically propagated;
Foreign key to iRule table;
Anchors the ABAC filter
definition to specific rule;
True/False value defines
whether filter specified is to
grant or deny object access;
Filter criteria; SQL wildcards
allowed;
Filter criteria; SQL wildcards
allowed;
Filter criteria; SQL wildcards
allowed;
distingusishedName
dtCreated
Appendix G
Table Name
configuration
Table Description
Main IADConnector configuration table; All other table
names are derived from this table; Table name can be
changed but the new name have to be set in
iADConnector.exe.config file under configuration key;
Column Name
DNSDomain
pk_id
pk_id
objectGuid
Column Description
Domain Fully Qualified
Domain Name; Specifies
configuration context;
Unique key name for the
configuration section;
Key value for given
configuration section;
Specifies configuration
context;
Domain Controller Fully
Qualified Domain Name;
This is the server that the
iADConnector synced with;
Domain Controller GUID;
This is the server that the
iADConnector synced with;
Last replication state
number;
Domain Fully Qualified
Domain Name;
Specifies database table sync
context;
Information about data/time
when the sync took place;
Automatically propagated;
Used for sync purposes;
Primary key, used to
uniquely identify the identity
within database context;
Automatically propagated;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Translated flag from
UserAccountControl
attribute;
Primary key, used to
uniquely identify the identity
within database context;
Automatically propagated;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Custom directory attribute;
Primary key, used to
uniquely identify the identity
within database context;
Automatically propagated;
Custom directory attribute;
sAMAccountName
distinguishedName
KeyName
KeyValue
Description
sync_control
dcDNS
invocationID
highestCommittedUSN
domainName
tableContext
dtSynced
user
contact
group
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
department
c
UAC_ACCOUNTDISABLE
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
department
c
UAC_ACCOUNTDISABLE
membership
objectSid
cn
description
objectGuid
sAMAccountName
distinguishedName
objectSid
cn
department
location
description
operatingSystem
group_dn
member_dn
group_cn
member_cn
Appendix H
Table Name
iPortal
Column Name
username
passwordHASH
status
Column Description
Username that have access to
iPortal and is a Resource
Owner entity in OAuth model
MD5 hashed password
Specifies whether the account is
active and can be used to
access the iPortal.
Appendix I
STORED PROCEDURES
IPORTALACCESSCONTROL
USE [iIdManagement]
GO
/****** Object: StoredProcedure [dbo].[iPortalAccessControl] Script Date: 08/17/2012 03:02:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
Greg Spyra
-- Create date: 12.08.2012
-- Description:
RBAC via ABAC iPortal access control
-- =============================================
CREATE PROCEDURE [dbo].[iPortalAccessControl]
AS
BEGIN
DECLARE @TBL TABLE
(
userName varchar(100),
[status] tinyint
)
INSERT INTO @TBL
SELECT
PORTAL.userName, 1 as status
FROM
iIdManagement.dbo.iRuleDef DEF
JOIN
iIdManagement.dbo.iRule RL
ON
(
DEF.fk_iRuleID = RL.pk_id
AND
RL.ruleName = 'iPortal'
)
JOIN
iADConnector.dbo.[user] INC
ON
DEF.isExclusion = 0
AND
(
INC.c LIKE DEF.country
OR
INC.division LIKE DEF.division
OR
INC.department LIKE DEF.department
OR
INC.distinguishedName LIKE DEF.distinguishedName
)
JOIN
iIdManagement.dbo.iRuleDef DEF_EX
ON
(
DEF_EX.fk_iRuleID = RL.pk_id
AND
DEF.isExclusion = 0
OR
(
DEF.country IS NULL OR (INC.c NOT LIKE DEF.country OR INC.c IS NULL)
AND
iIdManagement.dbo.iLinking LNK2
LNK2.fk_iIdentityID = LNK1.fk_iIdentityID
JOIN
iPortal.dbo.Accounts PORTAL
ON
PORTAL.userName = LNK2.fk_Account
JOIN
iIdManagement.dbo.iRule RL
ON
RL.ruleName = 'iPortal'
JOIN
iIdManagement.dbo.iRuleDef DEF
ON
AND
DEF.fk_iRuleID = RL.pk_id
(
DEF.isExclusion = 0
AND
(
LEN(DEF.country)>0 AND (EXC.c NOT LIKE DEF.country OR EXC.c IS
NULL)
OR
LEN(DEF.division)>0 AND (EXC.division NOT LIKE DEF.division OR
EXC.division IS NULL)
OR
LEN(DEF.department)>0
AND
(EXC.department
NOT
LIKE
)
MERGE INTO
iPortal.dbo.Accounts AS DST
USING
(
SELECT DISTINCT
T1.userName,
T1.[status]
FROM
@TBL T1
LEFT JOIN
@TBL T2
ON
(T1.userName = T2.userName
AND
T1.[status] < T2.[status]
)
WHERE
T2.userName IS NULL
) AS SRC
ON
DST.userName = SRC.userName
WHEN MATCHED THEN
UPDATE SET [status] = SRC.[status];
END
LINKIDENTITYFROMAD
USE [iIdManagement]
GO
/****** Object: StoredProcedure [dbo].[LinkIdentityFromAD] Script Date: 08/16/2012 00:55:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
Greg Spyra
-- Create date: 12.08.2012
-- Description:
Link Identity with AD account
-- =============================================
CREATE PROCEDURE [dbo].[LinkIdentityFromAD]
AS
BEGIN
INSERT INTO iIdManagement.dbo.iLinking
(fk_iIdentityID, fk_iSourceID, fk_AccountID)
SELECT
ID.pk_id,
SRC.pk_id,
LDAP.pk_id
FROM
iADConnector.dbo.[user] LDAP
JOIN
iIdManagement.dbo.iIdentity ID
ON
(
ID.Surname = LDAP.sn
AND
ID.FirstName = LDAP.givenName
)
JOIN
iIdManagement.dbo.iSource SRC
ON
AA
SRC.name = 'LDAP001'
LEFT JOIN
iIdManagement.dbo.iLinking LNK
ON
(
LNK.fk_iIdentityID = ID.pk_id
AND
LNK.fk_iSourceID = SRC.pk_id
AND
LNK.fk_AccountID = LDAP.pk_id
)
WHERE
LNK.fk_iIdentityID IS NULL
END
BB
LINKIDENTITYFROMIPORTAL
USE [iIdManagement]
GO
/****** Object: StoredProcedure [dbo].[LinkIdentityFromiPortal] Script Date: 08/16/2012 00:56:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
Greg Spyra
-- Create date: 12.08.2012
-- Description:
Link Identity with iPortal account
-- =============================================
CREATE PROCEDURE [dbo].[LinkIdentityFromiPortal]
(
@Surname varchar(100),
@FirstName varchar(100),
@userName varchar(100)
)
AS
BEGIN
INSERT INTO iIdManagement.dbo.iLinking
(fk_iIdentityID, fk_iSourceID, fk_Account)
SELECT
ID.pk_id,
SRC.pk_id,
PORTAL.userName
FROM
iPortal.dbo.[Accounts] PORTAL
JOIN
iIdManagement.dbo.iIdentity ID
ON
(
ID.Surname = @Surname
AND
ID.FirstName = @FirstName
AND
PORTAL.userName = @userName
)
JOIN
iIdManagement.dbo.iSource SRC
ON
SRC.name = 'iPortal'
LEFT JOIN
iIdManagement.dbo.iLinking LNK
ON
(
LNK.fk_iIdentityID = ID.pk_id
AND
LNK.fk_iSourceID = SRC.pk_id
AND
LNK.fk_Account = PORTAL.userName
)
WHERE
LNK.fk_iIdentityID IS NULL
END
CC
REGISTERIDENTITY
USE [iIdManagement]
GO
/****** Object: StoredProcedure [dbo].[RegisterIdentity] Script Date: 08/16/2012 00:57:10 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
Greg Spyra
-- Create date: 12.08.2012
-- Description:
Create Identity
-- =============================================
CREATE PROCEDURE [dbo].[RegisterIdentity]
(
@Surname AS varchar(100),
@FirstName AS varchar(100),
@MiddleName AS varchar(100) = NULL,
@Country AS varchar(50) = NULL,
@City AS varchar(100) = NULL,
@Description AS varchar(1024) = NULL
)
AS
BEGIN
INSERT INTO iIdManagement.dbo.iIdentity
(Surname, FirstName, MiddleName, Country, City, [Description])
VALUES
(@Surname, @FirstName, @MiddleName, @Country, @City, @Description)
END
REGISTERACCOUNT
USE [iPortal]
GO
/****** Object: StoredProcedure [dbo].[RegisterAccount] Script Date: 08/16/2012 00:57:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
Greg Spyra
-- Create date: 12.08.2012
-- Description:
Create iPortal account
-- =============================================
CREATE PROCEDURE [dbo].[RegisterAccount]
(
@userName AS varchar(100),
@passwordHASH AS varchar(1024),
@status AS tinyint = 1
)
AS
BEGIN
INSERT INTO Accounts
(userName, passwordHASH, [status])
VALUES
(@userName, @passwordHASH, @status)
END
DD
Appendix J
PROVISIONING.CMD
::******************************************************************************
:: Script Name:
:: Language: NT Shell
:: Author: Gregory Spyra
:: Project: MSc Dissertation
:: Date Written: 29 Jun 2012
:: Reason:
:: Notes:
:: Version: 1.0
:: Version History:
:: 1.0
29 Jun 2012
Created
::******************************************************************************
::******************************************************************************
::******************************************************************************
::******************************************************************************
::******************************************************************************
@ECHO Off
@SETLOCAL EnableDelayedExpansion
SET DOMAIN_DN=dc^=spyraconsulting,dc^=net
SET CUSTOMERS=NAPIER,RBS,NHS,GCHQ,ALL
SET
CUSTOMERS_LOCATIONS=00:ALL,00:NAPIER,UK:NAPIER,00:RBS,UK:RBS,00:NHS,UK:NHS,00:GCHQ,UK:GCHQ,USA:NAPIER,
USA:RBS,JP:RBS,PL:RBS,FR:RBS,FR:NAPIER
SET DEFAULT_OU=Users,SecurityGroups,DistributionGroups,Computers,Contacts
SET USER_OU=Users
SET GROUP_OU=SecurityGroups
SET DEFAULT_GROUPS=MultimediaServices,ITServices,HR,CustomerServices,FinanceServices
SET USER_PER_OU_LIMIT=500
SET LAST_USER_IDX=0
SET GROUP_PER_OU_LIMIT=10
::******************************************************************************
::******************************************************************************
::***************************************MAIN***********************************
::provision customers
FOR %%i IN (%CUSTOMERS%) Do DSADD OU "ou=%%~i,%DOMAIN_DN%"
::provision locations and default sub-structures
FOR %%i IN (%CUSTOMERS_LOCATIONS%) Do (
FOR /F "delims=: tokens=1,2" %%j In ("%%~i") Do (
::customer locations
DSADD OU "ou=%%~j,ou=%%~k,%DOMAIN_DN%" -Desc "Country Code:%%~j"
::sub-structure
FOR %%m In (%DEFAULT_OU%) Do (
DSADD OU "ou=%%~m,ou=%%~j,ou=%%~k,%DOMAIN_DN%" -Desc "Object Category:%%~m"
::provision users
FOR %%n In (%USER_OU%) Do (
IF {%%~m} EQU {%%~n} (
FOR /L %%i In (1,1,%USER_PER_OU_LIMIT%) Do (
SET /A LAST_USER_IDX=!LAST_USER_IDX!+1
DSADD
User
"cn=User!LAST_USER_IDX!,ou=%%~m,ou=%%~j,ou=%%~k,%DOMAIN_DN%"
"User!LAST_USER_IDX!" -fn "User" -ln "!LAST_USER_IDX!" -Company "%%~k"
EE
-SamID
)
)
)
::provision groups
FOR %%g In (%GROUP_OU%) Do (
IF {%%~m} EQU {%%~g} (
FOR %%h In (%DEFAULT_GROUPS%) Do (
SET GROUP_NAME=%%~k-%%~j-%%~h
DSADD
Group
"cn=!GROUP_NAME!,ou=%%~m,ou=%%~j,ou=%%~k,%DOMAIN_DN%"
"!GROUP_NAME!" -Desc "%%~h"
FOR /L %%i In (1,1,%GROUP_PER_OU_LIMIT%) Do (
DSADD Group "cn=!GROUP_NAME!%%~i,ou=%%~m,ou=%%~j,ou=%%~k,%DOMAIN_DN%"
"!GROUP_NAME!%%~i" -Desc "%%~h"
)
)
)
)
)
)
)
FF
-SamID
-SamID
Appendix K
IADCONNECTOR
IADCONNECTOR.CS
using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
namespace iADConnector
{
public partial class iADConnector : ServiceBase
{
protected EventLog objEventLog;
private int iMinutesElapsed;
DateTime dtLastRun;
public iADConnector()
{
InitializeComponent();
this.objEventLog
=
new
System.Diagnostics.EventLog("Application",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
}
protected override void OnStart(string[] args)
{
try
{
this.objTimer.Interval = 60000;
this.objTimer.Enabled = true;
this.dtLastRun = new DateTime();
this.iMinutesElapsed = 0;
// create message string
string strMessage = "timer successfullly started.\n\ninterval:\t" + (this.objTimer.Interval / 60000) + " minutes";
this.objEventLog.WriteEntry(strMessage, EventLogEntryType.Information, 1000);
using (iADConnectorEngine objReporter = new iADConnectorEngine() )
{
objReporter.OnMessage += this.WriteEventLogMessage;
objReporter.EncryptConfig();
objReporter.Dispose();
}
}
catch (Exception Error)
{
objEventLog.WriteEntry(Error.Message, EventLogEntryType.Error, 1200);
this.Stop();
}
}
protected override void OnStop()
{
try
{
this.objTimer.Enabled = false;
}
GG
".",
this.iMinutesElapsed
DateTime.Now.Hour)
!=
||
!=
(this.dtLastRun.Date
DateTime.Now.Date))
&& this.checkRunTime(strTime);
if ( bInterval || bSchedule )
{
using (iADConnectorEngine objReporter = new iADConnectorEngine())
{
objReporter.OnMessage += this.WriteEventLogMessage;
objReporter.GetCurrentState(bInterval, bSchedule);
}
this.iMinutesElapsed = bInterval
?0
: this.iMinutesElapsed + 1;
if(bSchedule) this.dtLastRun = DateTime.Now;
}
objTimer.Enabled = true;
}
catch (Exception Error)
{
this.objEventLog.WriteEntry(Error.Message, EventLogEntryType.Error, 1202);
objTimer.Enabled = true;
}
}
private void WriteEventLogMessage(Entry objEntry)
{
try
{
if (objEntry.SeverityLevel == Entry.Severity.Error)
{
this.objEventLog.WriteEntry((objEntry.Message.Length > Byte.MaxValue ?
objEntry.Message.Substring(0, Byte.MaxValue) : objEntry.Message), EventLogEntryType.Error, objEntry.EventId);
}
else if (objEntry.SeverityLevel == Entry.Severity.Warning)
{
this.objEventLog.WriteEntry((objEntry.Message.Length > Byte.MaxValue ?
objEntry.Message.Substring(0, Byte.MaxValue) : objEntry.Message), EventLogEntryType.Warning, objEntry.EventId);
}
else
{
HH
if (strDNSDomain != null)
{
strSQL = string.Format("SELECT KeyValue FROM {0} WHERE
Description
=
'{1}'
AND
DNSDomain
=
'{2}'
AND
KeyName
=
'{3}'",
ConfigurationManager.AppSettings["Configuration"].ToString(), strDescription, strDNSDomain, strKeyName);
}
else
{
strSQL = string.Format("SELECT KeyValue FROM {0} WHERE
Description = '{1}' AND KeyName = '{2}'", ConfigurationManager.AppSettings["Configuration"].ToString(), strDescription,
strKeyName);
}
using
(Handy.Sql
oSql
=
new
Handy.Sql(ConfigurationManager.ConnectionStrings["MigOneBankAD"].ConnectionString))
{
II
(Dictionary<string,
object>
dicRes
in
oSql.RetrieveData(strSQL))
{
strValue = dicRes["KeyValue"].ToString();
}
}
}
}
catch (Exception ex)
{
throw
new
Exception(String.Format("{0}::{1}",
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message));
}
return strValue;
}
}
}
JJ
new
IADCONNECTORENGINE.CS
using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using XtLdap;
namespace iADConnector
{
#region Global Variables
public enum UserAccountControl
{
UAC_SCRIPT =
0x0000001,
UAC_ACCOUNTDISABLE =
0x0000002,
UAC_HOMEDIR_REQUIRED =
0x0000008,
UAC_LOCKOUT =
0x0000010,
UAC_PASSWD_NOTREQD =
0x0000020,
UAC_PASSWD_CANT_CHANGE =
0x0000040,
UAC_ENCRYPTED_TEXT_PWD_ALLOWED =
0x0000080,
UAC_TEMP_DUPLICATE_ACCOUNT =
0x0000100,
UAC_NORMAL_ACCOUNT =
0x0000200,
UAC_INTERDOMAIN_TRUST_ACCOUNT =
0x0000800,
UAC_WORKSTATION_TRUST_ACCOUNT =
0x0001000,
UAC_SERVER_TRUST_ACCOUNT =
0x0002000,
UAC_DONT_EXPIRE_PASSWORD =
0x0010000,
UAC_MNS_LOGON_ACCOUNT =
0x0020000,
UAC_SMARTCARD_REQUIRED =
0x0040000,
UAC_TRUSTED_FOR_DELEGATION =
0x0080000,
UAC_NOT_DELEGATED =
0x0100000,
UAC_USE_DES_KEY_ONLY =
0x0200000,
UAC_DONT_REQ_PREAUTH =
0x0400000,
UAC_PASSWORD_EXPIRED =
0x0800000,
UAC_TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000
};
#endregion
#region Global Supporting Classes
public class Entry
{
public enum Severity
{
Verbose = 1, Info = 2, Warning = 3, Error = 4, Fatal = 5
};
public Severity SeverityLevel;
public string Message;
public int EventId;
}
public class UserCredentials : IDisposable
{
KK
LL
new
StackFrame(0,
{
return null;
}
else
{
try
{
IntPtr
System.Runtime.InteropServices.Marshal.SecureStringToBSTR(String);
pointerName
try
{
return
System.Runtime.InteropServices.Marshal.PtrToStringBSTR(pointerName);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(pointerName);
}
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
}
new
StackFrame(0,
Exception(string.Format("{0}::{1}",
#endregion
}
#endregion
class iADConnectorEngine : IDisposable
{
#region Variables
private bool bDisposed;
private List<string> lTruncated;
private long iHighestCommittedUsn = 0;
private string sConnectionString = null;
public delegate void MessageEventHandler(Entry objEntry);
public event MessageEventHandler OnMessage;
public string ConnectionString
{
get
{
return this.sConnectionString;
MM
new
StackFrame(0,
}
set
{
this.sConnectionString = value;
}
}
protected Entry objEntry;
#endregion
#region Constructors
public iADConnectorEngine()
{
try
{
this.bDisposed = false;
this.objEntry = new Entry();
this.lTruncated = new List<string>();
this.sConnectionString
ConfigurationManager.ConnectionStrings["iADConnector"].ConnectionString;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
#endregion
new
StackFrame(0,
NN
new
=
=
Convert.ToInt64(oDomainController.HighestCommittedUsn);
if ((Interval && this.GetDBConfig("Default",
null, "UserEnumeration") == "1")
||
(Schedule
&&
sTableName
this.GetTableName("user", sDomainName);
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
if
(!String.IsNullOrEmpty(sTableName))
{
using(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
{
List<string> lAttributesList = GetAttributeList(sTableName);
lAttributesList.Remove("sniff_time");
//get objects that were recently changed in AD
HashSet<string>
hsObjectsToUpdate
=
xtLdap.FindObjects(this.GetFilter("user",
XtLdap.LdapEngine.UniqueObjectIdentifier.distinguishedName, false);
OO
true),
Dictionary<string,
Dictionary<string,
xtLdap.RetrieveTranslatedUpdatedAttributes(hsObjectsToUpdate,
LdapEngine.UniqueObjectIdentifier.objectGuid.ToString());
string>>
dicUpdates
=
lAttributesList,
xtLdap.FindDeletedObjects(this.GetFilter("user",
false),
this.DeleteFromDb(sTableName,
LdapEngine.UniqueObjectIdentifier.objectGuid.ToString());
hsFreshDelState,
this.AdjustMembershipTableWithDnChanges(this.GetTableName("member",
sTableName, dicUpdates, LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sDomainName),
this.AdjustMembershipTableWithDeletions(this.GetTableName("member",
sTableName, hsFreshDelState.GetEnumerator(), LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sDomainName),
(Schedule
&&
string
sTableName
this.GetTableName("group", sDomainName);
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
PP
if
(!String.IsNullOrEmpty(sTableName))
{
using
(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
{
List<string> lAttributesList = GetAttributeList(sTableName);
lAttributesList.Remove("sniff_time");
//get
string>>
dicUpdates
true),
=
lAttributesList,
if
xtLdap.FindDeletedObjects(this.GetFilter("group",
false),
sDomainName),
this.AdjustMembershipTableWithDeletions(this.GetTableName("member",
sDomainName),
hsFreshDelState.GetEnumerator(), LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sTableName,
sTableName,
objEntry.Message
Entry.Severity.Error;
ex.Message;
CreateEventMessage(objEntry);
}
}
if ((Interval && this.GetDBConfig("Default",
(Schedule
&&
sTableName
this.GetTableName("computer", sDomainName);
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
if
(!String.IsNullOrEmpty(sTableName))
{
using
(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
string>>
dicUpdates
true),
=
lAttributesList,
if
xtLdap.FindDeletedObjects(this.GetFilter("computer",
false),
RR
this.AdjustMembershipTableWithDnChanges(this.GetTableName("member",
dicUpdates, LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sDomainName),
this.AdjustMembershipTableWithDeletions(this.GetTableName("member",
sDomainName),
hsFreshDelState.GetEnumerator(), LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sTableName,
sTableName,
(Schedule
&&
try
{
string
sTableName
this.GetTableName("contact", sDomainName);
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
if
(!String.IsNullOrEmpty(sTableName))
{
using
(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
{
List<string> lAttributesList = GetAttributeList(sTableName);
lAttributesList.Remove("sniff_time");
//get
objects that were recently changed in AD
SS
HashSet<string>
hsObjectsToUpdate
=
xtLdap.FindObjects(this.GetFilter("contact",
XtLdap.LdapEngine.UniqueObjectIdentifier.distinguishedName, false);
Dictionary<string,
Dictionary<string,
xtLdap.RetrieveTranslatedUpdatedAttributes(hsObjectsToUpdate,
LdapEngine.UniqueObjectIdentifier.objectGuid.ToString());
string>>
dicUpdates
true),
=
lAttributesList,
if
xtLdap.FindDeletedObjects(this.GetFilter("contact",
false),
sDomainName),
this.AdjustMembershipTableWithDeletions(this.GetTableName("member",
sDomainName),
hsFreshDelState.GetEnumerator(), LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sTableName,
sTableName,
(Schedule
&&
this.GetTableName("member", sDomainName);
sTableName
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
TT
(!String.IsNullOrEmpty(sTableName))
{
using
(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
{
List<string> lAttributesList = GetAttributeList(sTableName);
lAttributesList.Remove("sniff_time");
//get
LdapEngine.MembershipAction>>
true),
dicUpdates
=
if
UU
(Schedule
&&
sTableName
this.GetTableName("security", sDomainName);
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
if
(!String.IsNullOrEmpty(sTableName))
{
using
(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
{
List<string> lAttributesList = GetAttributeList( sTableName);
lAttributesList.Remove("sniff_time");
//get
objects that were recently changed in AD
HashSet<string>
hsObjectsToUpdate
=
xtLdap.FindObjects(this.GetFilter("security",
XtLdap.LdapEngine.UniqueObjectIdentifier.distinguishedName, false);
true),
hsObjectsToUpdate,
xtLdap.FindDeletedObjects(this.GetFilter("security",
this.DeleteFromDb(sTableName,
XtLdap.LdapEngine.UniqueObjectIdentifier.distinguishedName.ToString() );
false),
hsFreshDelState,
VV
objEntry.Message
Entry.Severity.Error;
ex.Message;
CreateEventMessage(objEntry);
}
}
if ((Interval && this.GetDBConfig("Default",
(Schedule
&&
sTableName
this.GetTableName("fsp", sDomainName);
long
iLastHighestCommittedUsn = this.GetLastSyncUsn(this.GetTableName("SyncControl", null), sServerGuid, sTableName);
if
(!String.IsNullOrEmpty(sTableName))
{
using
(LdapEngine xtLdap = new LdapEngine(
sServer,
iLastHighestCommittedUsn,
Credentials.UserName,
Credentials.Password))
{
List<string> lAttributesList = GetAttributeList(sTableName);
lAttributesList.Remove("sniff_time");
//get
objects that were recently changed in AD
HashSet<string>
hsObjectsToUpdate
=
xtLdap.FindObjects(this.GetFilter("fsp",
XtLdap.LdapEngine.UniqueObjectIdentifier.distinguishedName, false);
Dictionary<string,
Dictionary<string,
xtLdap.RetrieveTranslatedUpdatedAttributes(hsObjectsToUpdate,
LdapEngine.UniqueObjectIdentifier.objectGuid.ToString());
string>>
dicUpdates
true),
=
lAttributesList,
if
xtLdap.FindDeletedObjects(this.GetFilter("fsp",
false),
WW
this.AdjustMembershipTableWithDeletions(this.GetTableName("member",
sDomainName),
hsFreshDelState.GetEnumerator(), LdapEngine.UniqueObjectIdentifier.objectGuid, true);
sTableName,
new
// user encrypting
strSQL = string.Format("SELECT DNSDomain, KeyName, KeyValue FROM
{0} WHERE Description = 'Default' AND KeyName ='User'", ConfigurationManager.AppSettings.Get("configuration"));
foreach (Dictionary<string, object> dicRes in oSql.RetrieveData(strSQL))
{
string strName = dicRes["KeyName"].ToString();
string strValue = dicRes["KeyValue"].ToString();
XX
(!strValue.StartsWith("ID=",
StringComparison.OrdinalIgnoreCase))
{
if (strDomain != null && strDomain != "")
{
strSQL = string.Format("UPDATE {0} SET
KeyValue='ID={1}' WHERE Description = 'Default' AND KeyName ='User' AND DNSDomain='{2}'",
ConfigurationManager.AppSettings.Get("configuration"), SimpleCrypto.EncryptString(strValue), strDomain);
oSql.ExecuteNonSqlQuery(strSQL);
}
}
}
// password encrypting
strSQL = string.Format("SELECT DNSDomain, KeyName, KeyValue FROM
{0} WHERE Description = 'Default' AND KeyName ='Password'", ConfigurationManager.AppSettings.Get("configuration"));
foreach (Dictionary<string, object> dicRes in oSql.RetrieveData(strSQL))
{
string strName = dicRes["KeyName"].ToString();
string strValue = dicRes["KeyValue"].ToString();
string strDomain = dicRes["DNSDomain"].ToString();
if
(!strValue.StartsWith("PW=",
StringComparison.OrdinalIgnoreCase))
{
if (strDomain != null && strDomain != "")
{
strSQL = string.Format("UPDATE {0} SET
KeyValue='PW={1}' WHERE Description = 'Default' AND KeyName ='Password' AND DNSDomain='{2}'",
ConfigurationManager.AppSettings.Get("configuration"), SimpleCrypto.EncryptString(strValue), strDomain);
oSql.ExecuteNonSqlQuery(strSQL);
}
}
}
}
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
#endregion
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
//UPDATE
lDRow[NEW_ROW], oSql);
YY
lDRow[CUR_ROW],
}
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void UpdateDBState(string sTableName, List<Dictionary<string, string>> lUpdates, List<string>
lAttributes)
{
try
{
using (Handy.Sql oSql = new Handy.Sql(new SqlConnection(this.sConnectionString)))
{
foreach (StringBuilder sbPacket in this.GenerateBulkLoad(sTableName,
lUpdates, lAttributes))
{
oSql.ExecuteNonSqlQuery(sbPacket.ToString());
}
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void UpdateDBState(string sTableName, Dictionary<string, Dictionary<string, string>>
dicUpdates, LdapEngine.UniqueObjectIdentifier enUniqueAttribute, bool bFirstRun)
{
try
{
const int ROW_LIMIT = 1000;
StringBuilder sbSqlQuery = new StringBuilder();
StringBuilder sbSqlBulkUpdates = new StringBuilder();
StringBuilder sbSqlBulkInserts = new StringBuilder();
string sSqlQueryBase = bFirstRun
?String.Format("INSERT INTO [{0}] ([{{3}}],[{1}]) VALUES ({{4}})\n",
sTableName, enUniqueAttribute)
:String.Format("UPDATE [{0}] {{0}} WHERE [{{1}}]='{{2}}'
@@ROWCOUNT=0 INSERT INTO [{0}] ([{{3}}],[{1}]) VALUES ({{4}})\n", sTableName, enUniqueAttribute);
IF
int iRow = 0;
using (Handy.Sql oSql = new Handy.Sql(new SqlConnection(this.sConnectionString)))
{
foreach
(KeyValuePair<string,
Dictionary<string,
string>>
kvDictionariesUpdates in dicUpdates)
{
IEnumerator<KeyValuePair<string,
kvDictionariesUpdates.Value.GetEnumerator();
if (enUpdate.MoveNext())
ZZ
string>>
enUpdate
[{0}]=NULL", enUpdate.Current.Key);
sbSqlBulkInserts.Append("NULL");
}
else
{
string
sValue
enUpdate.Current.Value.Replace("'", "''");
sbSqlBulkUpdates.AppendFormat(@"SET
[{0}]='{1}'", enUpdate.Current.Key, sValue);
sbSqlBulkInserts.AppendFormat(@"'{0}'",
sValue);
}
while(enUpdate.MoveNext())
{
if
(String.IsNullOrEmpty(enUpdate.Current.Value))
sbSqlBulkUpdates.AppendFormat(@",[{0}]=NULL", enUpdate.Current.Key);
sbSqlBulkInserts.Append(",NULL");
}
else
{
string
sValue
enUpdate.Current.Value.Replace("'", "''");
sbSqlBulkUpdates.AppendFormat(@",[{0}]='{1}'", enUpdate.Current.Key, sValue);
sbSqlBulkInserts.AppendFormat(@",'{0}'", sValue);
}
}
sbSqlBulkInserts.AppendFormat(@",'{0}'",
kvDictionariesUpdates.Key);
}
enUniqueAttribute,
sbSqlBulkInserts);
kvDictionariesUpdates.Key,
sbSqlQuery.AppendFormat(sSqlQueryBase,
sbSqlBulkUpdates,
String.Join("],[",
kvDictionariesUpdates.Value.Keys.ToArray()),
iRow++;
if ((iRow % ROW_LIMIT) == 0)
{
if (sbSqlQuery.Length > 0)
{
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
sbSqlQuery = new StringBuilder();
}
}
sbSqlBulkUpdates = new StringBuilder();
sbSqlBulkInserts = new StringBuilder();
}
if (sbSqlQuery.Length > 0 & (iRow % ROW_LIMIT) > 0)
{
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
}
}
}
catch (Exception ex)
{
AAA
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private
void
UpdateDBState(string
sTableName,
Dictionary<string,
Dictionary<string,
LdapEngine.MembershipAction>> dicUpdates, bool bFirstRun)
{
try
{
const int ROW_LIMIT = 3000;
StringBuilder sbSqlQuery = new StringBuilder();
StringBuilder sbSqlAdd = new StringBuilder();
StringBuilder sbSqlDel = new StringBuilder();
string sCondAddBase = "UNION ALL SELECT '{0}','{1}','{2}','{3}'\n";
string sCondDelBase = "(group_dn='{0}' AND member_dn='{1}')\n";
string sSqlAddBase = bFirstRun
?String.Format(@"
INSERT INTO [{0}] (group_dn,member_dn,group_cn,member_cn)
SELECT
RQ.group_dn,
RQ.member_dn,
RQ.group_cn,
RQ.member_cn
FROM
({{0}}) RQ", sTableName)
:String.Format(@"
INSERT INTO [{0}] (group_dn,member_dn,group_cn,member_cn)
SELECT
RQ.group_dn,
RQ.member_dn,
RQ.group_cn,
RQ.member_cn
FROM
({{0}}) RQ
LEFT JOIN
[{0}] CUR
ON
(RQ.group_dn = CUR.group_dn AND RQ.member_dn =
CUR.member_dn)
WHERE CUR.group_dn IS NULL", sTableName);
string sSqlDelBase = String.Format(@"
DELETE FROM [{0}]
WHERE {{0}}", sTableName);
int iRow = 0;
using (Handy.Sql oSql = new Handy.Sql(new SqlConnection(this.sConnectionString)))
{
foreach
(KeyValuePair<string,
Dictionary<string,
LdapEngine.MembershipAction>> kvDictionariesUpdates in dicUpdates)
{
foreach (KeyValuePair<string, LdapEngine.MembershipAction>
kvUpdate in kvDictionariesUpdates.Value)
{
string
sGroupDn
=
kvDictionariesUpdates.Key.Replace("'", "''") ;
string sMemberDn = kvUpdate.Key.Replace("'", "''");
string sGroupCn = this.GetCnFromDn(sGroupDn);
string sMemberCn = this.GetCnFromDn(sMemberDn);
if
LdapEngine.MembershipAction.Add)
BBB
(kvUpdate.Value
==
if (sbSqlAdd.Length == 0)
{
sbSqlAdd.AppendFormat("SELECT
'{0}' as group_dn,'{1}' as member_dn,'{2}' as group_cn,'{3}' as member_cn\n", sGroupDn, sMemberDn, sGroupCn,
sMemberCn);
}
else
{
sbSqlAdd.AppendFormat(sCondAddBase, sGroupDn, sMemberDn, sGroupCn, sMemberCn);
}
}
else
{
if (sbSqlDel.Length == 0)
{
sbSqlDel.AppendFormat(sCondDelBase, sGroupDn, sMemberDn);
}
else
{
sbSqlDel.AppendFormat("OR\n"
sCondDelBase, sGroupDn, sMemberDn);
}
}
iRow++;
if ((iRow % ROW_LIMIT) == 0)
{
if (sbSqlDel.Length > 0)
{
sbSqlQuery.AppendFormat(sSqlDelBase + "\n", sbSqlDel);
}
if (sbSqlAdd.Length > 0)
{
sbSqlQuery.AppendFormat(sSqlAddBase, sbSqlAdd);
}
if (sbSqlQuery.Length > 0)
{
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
sbSqlQuery = new StringBuilder();
sbSqlAdd = new StringBuilder();
sbSqlDel = new StringBuilder();
}
}
}
if (sbSqlDel.Length > 0)
{
sbSqlQuery.AppendFormat(sSqlDelBase + "\n", sbSqlDel);
}
if (sbSqlAdd.Length > 0)
{
sbSqlQuery.AppendFormat(sSqlAddBase, sbSqlAdd);
}
if (sbSqlQuery.Length > 0 & (iRow % ROW_LIMIT) > 0)
{
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
}
CCC
}
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
DDD
MAX_RECORDS_PER_QUERY;
0;
==
hsObjectsToLoad.Count - 1)
{
sbSqlQuery.AppendLine( String.Format(@"[{0}] = '{1}'",
sUniqueIndex, sUniqueIdValue.Replace("'", "''")) );
foreach
(Dictionary<string,
object>
dicRes
in
oSql.RetrieveData(sbSqlQuery.ToString()))
{
Dictionary<string, string> dicRow = new
Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach(string sColumn in dicRes.Keys)
{
string sValue = null;
object oValue = dicRes[sColumn];
if (oValue.ToString().Length > 0)
{
if (oValue.GetType() ==
Type.GetType("System.DateTime"))
{
sValue
sValue
EEE
sKeyColumn,
sValueColumn);
string sSqlQueryBase = String.Format(@"SELECT {0} FROM [{1}] WHERE",
sColumns, sTableName);
int iBufferFrameSize =
int iObjectsLoaded =
MAX_RECORDS_PER_QUERY;
0;
FFF
while ( enumObject.MoveNext() )
{
string sUniqueIdValue = enumObject.Current;
if (--iBufferFrameSize == 0 || iObjectsLoaded
==
hsObjectsToLoad.Count - 1)
{
sbSqlQuery.AppendLine(String.Format(@"[{0}] = '{1}'",
(Dictionary<string,
object>
dicRes
in
oSql.RetrieveData(sbSqlQuery.ToString()))
{
string
sValue_Key
dicRes[sKeyColumn].ToString();
if
(!dicTableContent.ContainsKey(sValue_Key))
{
dicTableContent.Add(sValue_Key,
new HashSet<string>(StringComparer.OrdinalIgnoreCase));
dicTableContent[sValue_Key].Add(dicRes[sValueColumn].ToString());
}
else
(!dicTableContent[sValue_Key].Contains(dicRes[sValueColumn].ToString()))
{
if
dicTableContent[sValue_Key].Add(dicRes[sValueColumn].ToString());
}
}
iBufferFrameSize = MAX_RECORDS_PER_QUERY;
sbSqlQuery = new StringBuilder(sSqlQueryBase);
}
else
{
sbSqlQuery.AppendLine(String.Format(@"[{0}] = '{1}'
OR", sKeyColumn, sUniqueIdValue.Replace("'", "''")) );
}
iObjectsLoaded++;
}
}
return dicTableContent;
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
private
lDomainControllers)
{
DomainController
Exception(string.Format("{0}::{1}",
GetLastServerByUsn(string
sTableName,
new
StackFrame(0,
List<DomainController>
try
{
DomainController oDomainController = null;
string sServerName = String.Empty;
string sSqlCondition = String.Empty;
using
(Handy.Sql
oSql
=
Handy.Sql(ConfigurationManager.ConnectionStrings["iADConnector"].ConnectionString))
{
foreach (DomainController oDC in lDomainControllers)
{
GGG
new
OR ", oDC.GetDirectoryEntry().NativeGuid);
}
catch
{
}
}
if (sSqlCondition.Length > 0)
{
sSqlCondition = sSqlCondition.Substring(0, sSqlCondition.Length
- 4);
sSqlCondition);
(Dictionary<string,
DESC",
object>
sTableName,
dicRes
in
oDC
oSql.RetrieveData(sQuery))
{
IEnumerator<DomainController>
lDomainControllers.GetEnumerator();
while (oDomainController == null && oDC.MoveNext())
{
if
(oDC.Current.Name.Equals(dicRes["dcDNS"].ToString(), StringComparison.OrdinalIgnoreCase))
{
oDomainController = oDC.Current;
}
}
}
}
}
return oDomainController;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private long GetLastSyncUsn(string sTableName, string sInvocationId, string sContext)
{
try
{
long iHighestCommittedUsn = 0;
string sSqlClause = String.Empty;
using
(Handy.Sql
oSql
=
new
Handy.Sql(ConfigurationManager.ConnectionStrings["iADConnector"].ConnectionString))
{
sSqlClause = String.Format("invocationID = '{0}'", sInvocationId);
if (sContext != null)
{
sSqlClause += String.Format(" AND TableContext = '{0}'",
sContext);
}
string sQuery = String.Format(@"
SELECT TOP 1 highestCommittedUSN
HHH
highestCommittedUSN
DESC",
sTableName,
sSqlClause);
foreach (Dictionary<string, object> dicRes in oSql.RetrieveData(sQuery))
{
iHighestCommittedUsn
=
Convert.ToInt64(dicRes["highestCommittedUSN"]);
}
}
return iHighestCommittedUsn;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void SetLastSyncUsn(string sTableName, string sServerName, string sDomainName, string
sInvocationId, string sContext, long iHighestCommittedUsn)
{
try
{
using
(Handy.Sql
oSql
=
new
Handy.Sql(ConfigurationManager.ConnectionStrings["iADConnector"].ConnectionString))
{
string sSqlQuery = String.Format(@"
INSERT INTO {0}
(dcDNS,
highestCommittedUSN,
DomainName,
invocationID, TableContext)
VALUES
({1},{2},{3},{4},{5})",
sTableName,
String.Format("'{0}'", sServerName),
String.Format("{0}", iHighestCommittedUsn),
String.Format("'{0}'", sDomainName),
String.Format("'{0}'", sInvocationId),
String.Format("'{0}'", sContext)
);
oSql.ExecuteNonSqlQuery(sSqlQuery);
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private Dictionary<string, string> GetDiffs(Dictionary<string, string> dicSource, Dictionary<string,
string> dicDestination)
{
try
{
Dictionary<string,
string>
dicDiffs
=
new
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
foreach (string sSrc_Key in dicSource.Keys)
{
string sNewValue = dicSource[sSrc_Key];
string sOldValue = dicDestination[sSrc_Key];
if (dicDestination.ContainsKey(sSrc_Key))
{
if (sNewValue != null)
III
(!sNewValue.Equals(sOldValue,
StringComparison.OrdinalIgnoreCase))
{
dicDiffs.Add(sSrc_Key, sNewValue);
}
}
else if (sNewValue != sOldValue)
{
dicDiffs.Add(sSrc_Key, sNewValue);
}
}
else
{
dicDiffs.Add(sSrc_Key, sNewValue);
}
}
return dicDiffs;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private List<List<Dictionary<string, string>>> GetDiffs(Dictionary<string, Dictionary<string, string>>
dicDSource, Dictionary<string, Dictionary<string, string>> dicDDestination, string KeyAttribute)
{
try
{
List<List<Dictionary<string, string>>> lLDResult = new List<List<Dictionary<string,
string>>>();
foreach (string sIndex in dicDSource.Keys)
{
List<Dictionary<string, string>> lDRes = new List<Dictionary<string,
string>>();
Dictionary<string,
string>
dicDst
new
Dictionary<string,
Dictionary<string,
string>
dicSrc
new
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
string>(StringComparer.OrdinalIgnoreCase);
dicSrc = dicDSource[sIndex];
if (dicDDestination.TryGetValue(sIndex, out dicDst))
{
Dictionary<string, string> dicDiffs = GetDiffs(dicSrc, dicDst);
if (dicDiffs.Count > 0)
{
if (KeyAttribute != null)
{
lDRes.Add(new
Dictionary<string,string>(StringComparer.OrdinalIgnoreCase){{KeyAttribute.ToString(),
dicDst[KeyAttribute.ToString()]}});
}
else
{
lDRes.Add(dicDst);
}
lDRes.Add(dicDiffs);
}
}
else
{
lDRes.Add(null);
JJJ
lDRes.Add(dicSrc);
}
if (lDRes.Count > 0)
{
lLDResult.Add(lDRes);
}
}
return lLDResult;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private List<List<Dictionary<string, string>>> GetDiffs(Dictionary<string, HashSet<string>>
dicLSource, Dictionary<string, HashSet<string>> dicLDestination, string sKeyColumn, string sValueColumn)
{
try
{
List<List<Dictionary<string, string>>> lLDResult = new List<List<Dictionary<string,
string>>>();
//to add
foreach (string sIndex in dicLSource.Keys)
{
List<Dictionary<string, string>> lDRes;
HashSet<string>
HashSet<string>(StringComparer.OrdinalIgnoreCase);
HashSet<string>
HashSet<string>(StringComparer.OrdinalIgnoreCase);
lDst
new
lSrc
new
lSrc = dicLSource[sIndex];
if (dicLDestination.TryGetValue(sIndex, out lDst))
{
foreach (string sValue in lSrc)
{
lDRes = new List<Dictionary<string, string>>();
if
(!lDst.Contains(sValue,
StringComparer.OrdinalIgnoreCase))
{
//add CN feature
lDRes.Add(null);
lDRes.Add(new
string>(StringComparer.OrdinalIgnoreCase)
Dictionary<string,
{
{ sKeyColumn, sIndex },
{ sValueColumn, sValue },
{ sKeyColumn.Replace("_dn", "_cn"),
this.GetCnFromDn(sIndex) },
{
sValueColumn.Replace("_dn",
"_cn"), this.GetCnFromDn(sValue) }
});
}
if (lDRes.Count > 0)
{
lLDResult.Add(lDRes);
}
}
}
else
{
KKK
string>(StringComparer.OrdinalIgnoreCase)
Dictionary<string,
{
{ sKeyColumn, sIndex },
{ sValueColumn, sValue },
{
sKeyColumn.Replace("_dn",
"_cn"),
"_cn"),
this.GetCnFromDn(sIndex) },
sValueColumn.Replace("_dn",
this.GetCnFromDn(sValue) }
});
if (lDRes.Count > 0)
{
lLDResult.Add(lDRes);
}
}
}
//to remove
foreach (string sIndex in dicLDestination.Keys)
{
List<Dictionary<string, string>> lDRes;
HashSet<string>
HashSet<string>(StringComparer.OrdinalIgnoreCase);
HashSet<string>
HashSet<string>(StringComparer.OrdinalIgnoreCase);
lDst
new
lSrc
new
lDst = dicLDestination[sIndex];
if (dicLSource.TryGetValue(sIndex, out lSrc))
{
foreach (string sValue in lDst)
{
lDRes = new List<Dictionary<string, string>>();
if
(!lSrc.Contains(sValue,
StringComparer.OrdinalIgnoreCase))
{
lDRes.Add(new Dictionary<string, string>() {
{ sKeyColumn, sIndex }, { sValueColumn, sValue } });
lDRes.Add(null);
}
if (lDRes.Count > 0)
{
lLDResult.Add(lDRes);
}
}
}
else
{
foreach (string sValue in lSrc)
{
lDRes = new List<Dictionary<string, string>>();
lDRes.Add(new
sKeyColumn, sIndex }, { sValueColumn, sValue } });
Dictionary<string,
lDRes.Add(null);
if (lDRes.Count > 0)
{
lLDResult.Add(lDRes);
LLL
string>()
}
}
}
}
return lLDResult;
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
sUpdatedDn, kvUpdates.Key);
if (!bOnlyMember)
{
sbSqlQuery.AppendFormat(sSqlQueryGrpBase, sUpdatedDn, kvUpdates.Key);
}
}
iRow++;
if (sbSqlQuery.Length > 0 && (iRow % ROW_LIMIT) == 0)
{
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
sbSqlQuery = new StringBuilder();
}
MMM
out
}
if (sbSqlQuery.Length > 0 && (iRow % ROW_LIMIT) > 0)
{
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
}
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void AdjustMembershipTableWithDeletions(string sMembershipTable, string sObjectTable,
IEnumerator<string> enumDeleted, LdapEngine.UniqueObjectIdentifier enKeyAttribute, bool bOnlyMember)
{
try
{
const int ROW_LIMIT = 1000;
using (Handy.Sql oSql = new Handy.Sql(this.sConnectionString))
{
string sSqlQueryMbrBase = String.Format("DELETE MBR FROM [{0}] MBR
JOIN [{1}] OBJ ON (OBJ.distinguishedName=MBR.member_dn) WHERE OBJ.{2} IN ({{0}})\n", sMembershipTable,
sObjectTable, enKeyAttribute);
string sSqlQueryGrpBase = String.Format("DELETE MBR FROM [{0}] MBR
JOIN [{1}] OBJ ON (OBJ.distinguishedName=MBR.group_dn) WHERE OBJ.{2} IN ({{0}})\n", sMembershipTable,
sObjectTable, enKeyAttribute);
StringBuilder sbSqlQuery = new StringBuilder();
StringBuilder sbSqlCond = new StringBuilder();
int iRow = 0;
while (enumDeleted.MoveNext())
{
if ((iRow % ROW_LIMIT) == 0)
{
sbSqlCond.AppendFormat("'{0}'",
enumDeleted.Current);
}
else
{
sbSqlCond.AppendFormat(",'{0}'",
enumDeleted.Current);
}
iRow++;
if ((iRow % ROW_LIMIT) == 0)
{
sbSqlQuery.AppendFormat(sSqlQueryMbrBase,
sbSqlCond);
if (!bOnlyMember)
{
sbSqlQuery.AppendFormat(sSqlQueryGrpBase, sbSqlCond);
}
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
sbSqlQuery = new StringBuilder();
sbSqlCond = new StringBuilder();
}
}
if (sbSqlCond.Length > 0 && (iRow % ROW_LIMIT) > 0)
{
sbSqlQuery.AppendFormat(sSqlQueryMbrBase, sbSqlCond);
if (!bOnlyMember)
NNN
sbSqlCond);
}
oSql.ExecuteNonSqlQuery(sbSqlQuery.ToString());
}
}
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
FROM
OOO
new
StackFrame(0,
try
{
List<string> lDomains = new List<string>();
return lDomains;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
private string GetTableName(string strClass, string strDomain)
{
string strTable = null;
new
StackFrame(0,
switch (strClass.ToLower())
{
case "user":
strTable = this.GetDBConfig("Default", strDomain, "UserTable");
break;
case "ged":
strTable = this.GetDBConfig("Default", strDomain, "GEDTable");
break;
case "group":
strTable = this.GetDBConfig("Default", strDomain, "GroupTable");
break;
case "computer":
strTable = this.GetDBConfig("Default", strDomain, "ComputerTable");
break;
case "contact":
strTable = this.GetDBConfig("Default", strDomain, "ContactTable");
break;
case "member":
strTable = this.GetDBConfig("Default", strDomain, "MembershipTable");
break;
case "security":
strTable = this.GetDBConfig("Default", strDomain, "SecurityTable");
break;
case "fsp":
strTable = this.GetDBConfig("Default", strDomain, "FspTable");
break;
default:
strTable = this.GetDBConfig("Default", strDomain, strClass);
break;
}
return strTable;
}
private string GetDBConfig(string strDescription, string strDNSDomain, string strKeyName)
{
string strValue = null;
try
{
string strSQL = null;
if (strDescription != null && strDescription != String.Empty && strKeyName != null
&& strKeyName != String.Empty)
PPP
{
if (strDNSDomain != null)
{
strSQL = string.Format("SELECT KeyValue FROM {0} WHERE
Description
=
'{1}'
AND
DNSDomain
=
'{2}'
AND
KeyName
=
'{3}'",
ConfigurationManager.AppSettings["Configuration"].ToString(), strDescription, strDNSDomain, strKeyName);
}
else
{
strSQL = string.Format("SELECT KeyValue FROM {0} WHERE
Description = '{1}' AND KeyName = '{2}'", ConfigurationManager.AppSettings["Configuration"].ToString(), strDescription,
strKeyName);
}
using
(Handy.Sql
oSql
=
new
Handy.Sql(ConfigurationManager.ConnectionStrings["iADConnector"].ConnectionString))
{
foreach
(Dictionary<string,
object>
dicRes
in
oSql.RetrieveData(strSQL))
{
strValue = dicRes["KeyValue"].ToString();
}
}
}
}
catch (Exception ex)
{
throw
new
Exception(String.Format("{0}::{1}",
new
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message));
}
return strValue;
}
public void UpdateRecord(string sTableName, Dictionary<string, string> dicCur, Dictionary<string,
string> dicNew, Handy.Sql oSql)
{
try
{
string sSqlQuery = String.Empty;
string sClause = String.Empty;
string sUpd = String.Empty;
foreach (string sKey in dicNew.Keys)
{
string sValue = dicNew[sKey];
if (sValue == null)
{
sUpd += String.Format(@",[{0}]=NULL", sKey);
}
else
{
sUpd += String.Format(@",[{0}]='{1}'", sKey,sValue.Replace(@"'",
@"''"));
}
}
sUpd = sUpd.TrimStart(',');
foreach (string sKey in dicCur.Keys)
{
string sValue = dicCur[sKey];
if (sValue == null)
{
sClause += String.Format(@" AND [{0}] Is NULL", sKey);
}
else
{
QQQ
+=
String.Format(@"
AND
[{0}]='{1}'",
sKey,
sValue.Replace(@"'", @"''"));
}
}
sClause = sClause.Substring(4);
sSqlQuery = String.Format(@"
UPDATE {0}
SET {1}
WHERE {2}",
sTableName, sUpd, sClause);
oSql.ExecuteNonSqlQuery(sSqlQuery);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public void InsertRecord(string sTableName, Dictionary<string, string> dicNew, Handy.Sql oSql)
{
try
{
string sSqlQuery = String.Empty;
string sColumns = String.Empty;
string sValues = String.Empty;
foreach (string sKey in dicNew.Keys)
{
string sValue = dicNew[sKey];
sColumns += String.Format(@",[{0}]", sKey);
if (sValue == null)
{
sValues += String.Format(@",NULL");
}
else
{
sValues += String.Format(@",'{0}'", sValue.Replace(@"'", @"''"));
}
}
sColumns = sColumns.TrimStart(',');
sValues = sValues.TrimStart(',');
sSqlQuery = String.Format(@"
INSERT INTO {0}
({1})
VALUES ({2})",
sTableName, sColumns, sValues);
oSql.ExecuteNonSqlQuery(sSqlQuery);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public void DeleteRecord(string sTableName, Dictionary<string, string> dicCur, Handy.Sql oSql)
{
try
{
string sSqlQuery = String.Empty;
string sClause = String.Empty;
RRR
sKey,
sValue.Replace(@"'", @"''"));
}
}
sClause = sClause.Substring(4);
sSqlQuery = String.Format(@"
DELETE FROM {0}
WHERE {1}",
sTableName, sClause);
oSql.ExecuteNonSqlQuery(sSqlQuery);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
StackFrame(0,
}
}
sbSqlBulk.Remove(sbSqlBulk.Length - 1, 1);
}
SSS
else
{
sbSqlBulk.AppendLine("\nUNION ALL SELECT");
foreach (string sKey in lAttributes)
{
string sValue = String.Empty;
if (dicRecord.TryGetValue(sKey, out sValue))
{
sbSqlBulk.AppendFormat(@"'{0}',",
sValue.Replace("'", "''"));
}
else
{
sbSqlBulk.AppendFormat(@"NULL,");
}
}
sbSqlBulk.Remove(sbSqlBulk.Length - 1, 1);
}
iRow++;
if ((iRow % ROW_LIMIT) == 0)
{
if (sbSqlBulk.Length > 0)
{
BulkLoadPackets.Add(sbSqlBulk);
sbSqlBulk = new StringBuilder(String.Format("INSERT
INTO [{0}] ({1})", sTableName, String.Join(",", lAttributes.ToArray())));
}
}
}
if (sbSqlBulk.Length > 0 & (iRow % ROW_LIMIT) > 0)
{
BulkLoadPackets.Add(sbSqlBulk);
}
return BulkLoadPackets;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
new
StackFrame(0,
}
#endregion
#region Helper Private Methods
private string DecryptString(string strInput)
{
try
{
if (strInput != null && strInput.Length > 0)
{
if (strInput.StartsWith("ID=") || strInput.StartsWith("PW="))
{
return
SimpleCrypto.DecryptString(strInput.Substring(3,
strInput.Length - 3));
}
else
{
return SimpleCrypto.DecryptString(strInput);
}
}
else
TTT
{
return strInput;
}
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
new
&&
Exception(string.Format("{0}::{1}",
UUU
new
StackFrame(0,
{
return bExtended
? @"(&(objectCategory=person)(objectClass=user))"
: @"(objectClass=user)";
}
else if (sObjectClass.Equals("ged", StringComparison.OrdinalIgnoreCase))
{
return @"(&(objectClass=csgPerson)(csgPersonStatus=active))";
}
else if (sObjectClass.Equals("group", StringComparison.OrdinalIgnoreCase))
{
return bExtended
? @"(&(objectCategory=group)(objectClass=group))"
: @"(objectClass=group)";
}
else if (sObjectClass.Equals("computer", StringComparison.OrdinalIgnoreCase))
{
return bExtended
? @"(&(objectCategory=computer)(objectClass=computer))"
: @"(objectClass=computer)";
}
else if (sObjectClass.Equals("security", StringComparison.OrdinalIgnoreCase))
{
return bExtended
?
@"(&(objectCategory=organizationalUnit)(objectClass=organizationalUnit))"
: @"(objectClass=organizationalUnit)";
}
else if (sObjectClass.Equals("fsp", StringComparison.OrdinalIgnoreCase))
{
return
@"(&(objectClass=foreignSecurityPrincipal)(objectClass=foreignSecurityPrincipal))";
}
else if (sObjectClass.Equals("contact", StringComparison.OrdinalIgnoreCase))
{
return @"(&(objectCategory=person)(objectClass=contact))";
}
else
{
return @"(objectClass=*)";
}
}
private string[] GetSiteServers(string DomainName, string ADSite)
{
try
{
return this.GetSiteServers(DomainName, ADSite, null, null);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private string[] GetSiteServers(string DomainName, string ADSite, string UserID, string UserPW)
{
string sDomainControllers = null;
try
{
using (Domain oDomain = UserID != null && UserPW != null
?
Domain.GetDomain(new
DirectoryContext(DirectoryContextType.Domain, DomainName, UserID, UserPW))
:
Domain.GetDomain(new
DirectoryContext(DirectoryContextType.Domain, DomainName)))
VVV
{
DomainControllerCollection colDomControllers = (ADSite != null)
? oDomain.FindAllDomainControllers(ADSite)
: oDomain.FindAllDomainControllers();
if (colDomControllers.Count == 0)
{
colDomControllers = oDomain.FindAllDomainControllers();
}
foreach (DomainController DC in colDomControllers)
{
sDomainControllers += String.Format(";{0}", DC.Name);
}
}
sDomainControllers = sDomainControllers.TrimStart(';');
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
return sDomainControllers.Split(';');
}
private List<DomainController> GetSiteDC(string DomainName, string ADSite, string UserID, string
UserPW)
{
try
{
List<DomainController> lDomainControllers = new List<DomainController>();
using (Domain oDomain = UserID != null && UserPW != null
?
Domain.GetDomain(new
DirectoryContext(DirectoryContextType.Domain, DomainName, UserID, UserPW))
:
Domain.GetDomain(new
DirectoryContext(DirectoryContextType.Domain, DomainName)))
{
DomainControllerCollection colDomControllers = (ADSite != null)
? oDomain.FindAllDomainControllers(ADSite)
: oDomain.FindAllDomainControllers();
if (colDomControllers.Count == 0)
{
colDomControllers = oDomain.FindAllDomainControllers();
}
foreach (DomainController oDC in colDomControllers)
{
lDomainControllers.Add(oDC);
}
}
return lDomainControllers;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void CreateEventMessage(Entry objEventEntry)
{
try
{
this.objEntry = objEventEntry;
if (OnMessage != null)
{
OnMessage(this.objEntry);
WWW
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
private void GetEventMessage(Entry objEventEntry)
{
try
{
this.objEntry = objEventEntry;
CreateEventMessage(this.objEntry);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bDisposing)
{
if (!this.bDisposed)
{
if (bDisposing)
{
}
this.bDisposed = true;
}
}
#endregion
}
}
XXX
new
StackFrame(0,
new
StackFrame(0,
SIMPLECRYPTO.CS
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
class SimpleCrypto :IDisposable
{
#region Private Variables
private bool bDisposed;
#endregion
#region Constructors
public SimpleCrypto()
{
this.bDisposed = false;
}
#endregion
#region Public Methods
public string Encrypt(string PlainText)
{
try
{
return
Convert.ToBase64String(PlainText.ToCharArray().Select(cChar
=>
(byte)(~Convert.ToByte(cChar))).ToArray());
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}", new StackFrame(0, true).GetMethod().Name,
ex.Message));
}
}
public string Decrypt(string DecryptedText)
{
try
{
return
new
String(
Convert.ToChar((byte)~bByte)).ToArray() );
Convert.FromBase64String(DecryptedText).Select(bByte
=>
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}", new StackFrame(0, true).GetMethod().Name,
ex.Message));
}
}
#endregion
#region Public Methods
public static string EncryptString(string PlainText)
{
try
{
return
Convert.ToBase64String(PlainText.ToCharArray().Select(cChar
=>
(byte)(~Convert.ToByte(cChar))).ToArray());
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}", new StackFrame(0, true).GetMethod().Name,
ex.Message));
YYY
}
}
public static string DecryptString(string DecryptedText)
{
try
{
return
new
String(Convert.FromBase64String(DecryptedText).Select(bByte
Convert.ToChar((byte)~bByte)).ToArray());
=>
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}", new StackFrame(0, true).GetMethod().Name,
ex.Message));
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bDisposing)
{
if (!this.bDisposed)
{
if (bDisposing)
{
}
this.bDisposed = true;
}
}
#endregion
}
ZZZ
HANDY.CS
using System;
using System.Collections.Generic;
using System.Data;
//using System.Data.SqlClient;
using System.Diagnostics;
using System.DirectoryServices.Protocols;
using System.Linq;
using System.Net;
namespace Handy
{
class Ldap : IDisposable
{
#region Constants
private const int CONN_TIME_OUT = 600; //seconds
#endregion
#region Variables
private bool bDisposed;
private string sBaseSearchDn = null;
private string[] aDcServers = null;
private Int32 iPortNumber = 389;
private Int32 iPageSize = 500;
private NetworkCredential netCredentials = null;
//class properties
public string BaseSearchDn
{
get
{
return this.sBaseSearchDn;
}
set
{
this.sBaseSearchDn = value;
}
}
public string[] DomainControllers
{
get
{
return this.aDcServers;
}
set
{
this.aDcServers = value;
}
}
public Int32 Port
{
get
{
return this.iPortNumber;
}
set
{
AAAA
this.iPortNumber = value;
}
}
public Int32 PageSize
{
get
{
return this.iPageSize;
}
set
{
this.iPageSize = value;
}
}
public NetworkCredential NetworkCredentials
{
set
{
this.netCredentials = value;
}
}
#endregion
#region Constructors
public Ldap(string DomainName, string UserName, string Password)
{
try
{
this.bDisposed = false;
netCredentials = new NetworkCredential();
netCredentials.UserName = UserName;
netCredentials.Password = Password;
this.aDcServers = new string[] { DomainName };
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public Ldap(string DomainName, string UserName, string Password, string BaseDn, Int32 Port)
{
try
{
this.bDisposed = false;
this.netCredentials = new NetworkCredential();
this.netCredentials.UserName = UserName;
this.netCredentials.Password = Password;
this.iPortNumber = Port;
this.BaseSearchDn = BaseDn;
this.aDcServers = new string[] { DomainName };
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
#endregion
BBBB
new
StackFrame(0,
rcPageResponse
(SearchResponse)oLdapConnection.SendRequest(srRequest);
(PageResultResponseControl)dirRes.Controls[0];
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}", new
StackFrame(0, true).GetMethod().Name, ex.Message));
}
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
Dictionary<string, object> dicProperties =
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach
(string
sAttribute
in
AttributesToLoad)
{
if
(srEntry.Attributes.Contains(sAttribute))
CCCC
dicProperties.Add(sAttribute,
srEntry.Attributes[sAttribute].GetValues(srEntry.Attributes[sAttribute][0].GetType()));
}
}
yield return dicProperties;
}
}
rcPageRequest.Cookie = rcPageResponse.Cookie;
}
while (Convert.ToBoolean(rcPageResponse.Cookie.Length));
}
//NOT PAGED
else
{
try
{
dirRes
(SearchResponse)oLdapConnection.SendRequest(srRequest);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
StackFrame(0, true).GetMethod().Name, ex.Message));
}
new
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
Dictionary<string, object> dicProperties = new
Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach (string sAttribute in AttributesToLoad)
{
if (srEntry.Attributes.Contains(sAttribute))
{
dicProperties.Add(sAttribute,
srEntry.Attributes[sAttribute].GetValues(srEntry.Attributes[sAttribute][0].GetType()));
}
}
yield return dicProperties;
}
}
}
//dispose
if (dirRes != null) { dirRes = null; }
if (srRequest != null) { srRequest = null; }
if (rcPageRequest != null) { rcPageRequest = null; }
if (rcPageResponse != null) { rcPageResponse = null; }
}
}
#endregion
#region Private Methods
private LdapConnection OpenLdapConnection(string sServerName, NetworkCredential netCred)
{
try
{
LdapDirectoryIdentifier
oLdapDirectory
=
LdapDirectoryIdentifier(sServerName, this.Port);
new
DDDD
oLdapConnection.Timeout = TimeSpan.FromSeconds(CONN_TIME_OUT);
oLdapConnection.SessionOptions.TcpKeepAlive = true;
oLdapConnection.SessionOptions.ProtocolVersion = 3;
//prevents ldap connection from connecting to other servers during session
oLdapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
oLdapConnection.AutoBind = false;
return oLdapConnection;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bDisposing)
{
if (!this.bDisposed)
{
if (bDisposing)
{
}
this.bDisposed = true;
}
}
#endregion
}
class Sql : IDisposable
{
#region Variables
private bool bDisposed;
private int iCommandTimeout = 300;
private string sConnectionString;
private System.Data.SqlClient.SqlConnection oSqlConnection;
public int CommandTimeout
{
get
{
return this.iCommandTimeout;
}
set
{
this.iCommandTimeout = value;
}
}
public string ConnectionString
{
get
{
EEEE
new
StackFrame(0,
return this.sConnectionString;
}
set
{
this.sConnectionString = value;
}
}
public System.Data.SqlClient.SqlConnection sqlConnection
{
get
{
return this.oSqlConnection;
}
set
{
this.oSqlConnection = value;
}
}
#endregion
#region Constructors
public Sql(string SqlConnectionString)
{
this.bDisposed = false;
this.sConnectionString = SqlConnectionString;
}
public Sql(string SqlConnectionString, int CommandTimeout)
{
this.bDisposed = false;
this.iCommandTimeout = CommandTimeout;
this.sConnectionString = SqlConnectionString;
}
public Sql(System.Data.SqlClient.SqlConnection sqlConnection)
{
this.bDisposed = false;
this.sqlConnection = sqlConnection;
if (this.sqlConnection.State != ConnectionState.Open) this.sqlConnection.Open();
}
public Sql(System.Data.SqlClient.SqlConnection sqlConnection, int CommandTimeout)
{
this.bDisposed = false;
this.iCommandTimeout = CommandTimeout;
this.sqlConnection = sqlConnection;
if (this.sqlConnection.State != ConnectionState.Open) this.sqlConnection.Open();
}
#endregion
#region Public Methods
public IEnumerable<Dictionary<string, object>> RetrieveData(string SqlQuery)
{
using
(System.Data.SqlClient.SqlConnection
sqlConnection
System.Data.SqlClient.SqlConnection(this.sConnectionString))
{
try
{
sqlConnection.Open();
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}", new
true).GetMethod().Name, ex.Message));
}
FFFF
new
StackFrame(0,
using
(System.Data.SqlClient.SqlCommand
sqlCommand
=
System.Data.SqlClient.SqlCommand(SqlQuery, sqlConnection))
{
sqlCommand.CommandTimeout = this.CommandTimeout;
using
(System.Data.SqlClient.SqlDataReader
sqlReader
sqlCommand.ExecuteReader())
{
while (sqlReader.Read())
{
Dictionary<string,
object>
dicRecord
=
Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < sqlReader.FieldCount; i++)
{
string sKey = sqlReader.GetName(i);
new
new
if (!dicRecord.ContainsKey(sKey))
{
dicRecord.Add(sKey,
sqlReader.GetValue(i));
}
}
yield return dicRecord;
}
}
}
}
}
public void ExecuteNonSqlQuery(string SqlQuery)
{
try
{
if (this.sqlConnection != null)
{
using
(System.Data.SqlClient.SqlCommand
sqlCommand
=
System.Data.SqlClient.SqlCommand(SqlQuery, this.sqlConnection))
{
sqlCommand.CommandTimeout = this.CommandTimeout;
sqlCommand.ExecuteNonQuery();
}
}
else
{
using (System.Data.SqlClient.SqlConnection sqlConnection =
System.Data.SqlClient.SqlConnection(this.ConnectionString))
{
try
{
sqlConnection.Open();
}
catch (Exception ex)
{
throw new Exception(string.Format("{0}::{1}",
StackFrame(0, true).GetMethod().Name, ex.Message));
}
using (System.Data.SqlClient.SqlCommand sqlCommand =
System.Data.SqlClient.SqlCommand(SqlQuery, sqlConnection))
{
sqlCommand.CommandTimeout
this.CommandTimeout;
sqlCommand.ExecuteNonQuery();
}
}
}
}
catch (Exception ex)
{
GGGG
new
new
new
new
=
Exception(string.Format("{0}::{1}",
HHHH
new
StackFrame(0,
XTLDAP.CS
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices.Protocols;
using System.Globalization;
using System.Net;
using System.Runtime.CompilerServices;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Security.AccessControl;
namespace XtLdap
{
class LdapEngine :IDisposable
{
#region Constants
private const int MAX_DC_POOL_THREADS = 4;
private const int CPU_CORE_NO_PER_DC = 4;
private const int NUMBER_OF_OPEN_TCP_CONNECTIONS = 5;
private const int CONN_TIME_OUT = 600; //seconds
private enum UserAccountControl
{
UAC_SCRIPT =
0x0000001,
UAC_ACCOUNTDISABLE =
0x0000002,
UAC_HOMEDIR_REQUIRED =
0x0000008,
UAC_LOCKOUT =
0x0000010,
UAC_PASSWD_NOTREQD =
0x0000020,
UAC_PASSWD_CANT_CHANGE =
0x0000040,
UAC_ENCRYPTED_TEXT_PWD_ALLOWED =
0x0000080,
UAC_TEMP_DUPLICATE_ACCOUNT =
0x0000100,
UAC_NORMAL_ACCOUNT =
0x0000200,
UAC_INTERDOMAIN_TRUST_ACCOUNT =
0x0000800,
UAC_WORKSTATION_TRUST_ACCOUNT =
0x0001000,
UAC_SERVER_TRUST_ACCOUNT =
0x0002000,
UAC_DONT_EXPIRE_PASSWORD =
0x0010000,
UAC_MNS_LOGON_ACCOUNT =
0x0020000,
UAC_SMARTCARD_REQUIRED =
0x0040000,
UAC_TRUSTED_FOR_DELEGATION =
0x0080000,
UAC_NOT_DELEGATED =
0x0100000,
UAC_USE_DES_KEY_ONLY =
0x0200000,
UAC_DONT_REQ_PREAUTH =
0x0400000,
UAC_PASSWORD_EXPIRED =
0x0800000,
UAC_TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000
};
#endregion
#region Variables
private bool bDisposed;
private string[] aDcServers = null;
private string sBaseSearchDn = null;
private Int32 iPortNumber = 389;
private Int32 iPageSize = 500;
private NetworkCredential netCredentials = null;
IIII
null;
JJJJ
return this.iPageSize;
}
set
{
this.iPageSize = value;
}
}
public long HighestCommitedUSN
{
get
{
return this.iHighestCommittedUSN;
}
set
{
this.iHighestCommittedUSN = value;
}
}
public string[] DomainControllers
{
get
{
return this.aDcServers;
}
set
{
this.aDcServers = value;
}
}
public NetworkCredential NetworkCredentials
{
set
{
this.netCredentials = value;
}
}
#endregion
#region Constructors
public LdapEngine()
{
try
{
this.bDisposed = false;
aDcServers
this.GetSiteServers(Domain.GetCurrentDomain().Name.ToString(),
null);
this.LoadLdapAttributes();
this.LoadExtendedRights();
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
true).GetMethod().Name, ex.Message));
}
}
public LdapEngine(string[] DomainControllers, string UserName, string Password)
{
try
{
this.bDisposed = false;
KKKK
StackFrame(0,
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public LdapEngine(string[] DomainControllers, string UserName, string Password, string BaseDn, Int32
Port)
{
try
{
this.bDisposed = false;
this.netCredentials = new NetworkCredential();
netCredentials.UserName = UserName;
netCredentials.Password = Password;
this.iPortNumber = Port;
this.BaseSearchDn = BaseDn;
this.aDcServers = DomainControllers;
this.LoadLdapAttributes();
this.LoadExtendedRights();
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public LdapEngine(string DomainController, long HighestCommittedUSN, string UserName, string
Password)
{
try
{
this.bDisposed = false;
this.iHighestCommittedUSN = HighestCommittedUSN;
this.aDcServers = new string[] { DomainController };
this.netCredentials = new NetworkCredential();
netCredentials.UserName = UserName;
netCredentials.Password = Password;
this.LoadLdapAttributes();
this.LoadExtendedRights();
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
public LdapEngine(string DomainName, string UserName, string Password)
{
try
{
this.bDisposed = false;
LLLL
new
StackFrame(0,
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public LdapEngine(string DomainName, string ADSite, string UserName, string Password)
{
this.netCredentials.UserName =
UserName;
this.netCredentials.Password =
Password;
this.aDcServers = this.GetSiteServers(DomainName, null, UserName, Password);
this.LoadLdapAttributes();
this.LoadExtendedRights();
this.bDisposed = false;
}
#endregion
#region Public Methods
public HashSet<string> FindObjects(string LdapFilter, UniqueObjectIdentifier KeyAttribute, bool
ShowDeleted)
{
HashSet<string> hsSearchResult = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
try
{
MMMM
using
(LdapConnection
oLdapConnection
this.OpenLdapConnection(this.aDcServers[0], this.netCredentials))
{
SearchResponse dirRes = null;
SearchRequest srRequest = null;
PageResultRequestControl rcPageRequest = null;
PageResultResponseControl rcPageResponse = null;
string sAttribute = KeyAttribute.ToString();
string sServerName = oLdapConnection.SessionOptions.HostName;
string
sBaseDn
=
(this.sBaseSearchDn
==
null
||
this.sBaseSearchDn.Equals(String.Empty))
?
sServerName.Substring(sServerName.IndexOf('.') + 1).Replace(".", ",DC="))
: this.sBaseSearchDn;
String.Format("DC={0}",
if (this.iHighestCommittedUSN > 0)
{
LdapFilter = String.Format(@"(&(uSNChanged>={0})({1}))",
iHighestCommittedUSN, LdapFilter);
}
srRequest = new SearchRequest(
sBaseDn,
LdapFilter,
System.DirectoryServices.Protocols.SearchScope.Subtree,
sAttribute
);
if (ShowDeleted)
{
srRequest.Controls.Add(new ShowDeletedControl());
}
rcPageRequest = new PageResultRequestControl();
rcPageRequest.PageSize = this.iPageSize;
srRequest.Controls.Add(rcPageRequest);
do
{
dirRes
(SearchResponse)oLdapConnection.SendRequest(srRequest);
rcPageResponse
(PageResultResponseControl)dirRes.Controls[0];
dicAttributeList.ContainsKey(sAttribute)
StringComparison.OrdinalIgnoreCase))
=
=
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
string sValue = null;
if (srEntry.Attributes.Contains(sAttribute) &&
&&
dicAttributeList[sAttribute].Equals("Sid",
{
object[]
aValues
srEntry.Attributes[sAttribute].GetValues(Type.GetType("System.Byte[]"));
for (int i = 0; i < aValues.Length;
i++)
{
sValue
NNNN
else
(srEntry.Attributes.Contains(sAttribute)
&&
dicAttributeList.ContainsKey(sAttribute)
dicAttributeList[sAttribute].Equals("Octet", StringComparison.OrdinalIgnoreCase))
{
object[]
aValues
srEntry.Attributes[sAttribute].GetValues(Type.GetType("System.Byte[]"));
sValue
=
Guid((byte[])aValues[0]).ToString();
}
else
{
sValue
srEntry.Attributes[sAttribute][0].ToString();
}
hsSearchResult.Add(sValue);
}
}
rcPageRequest.Cookie = rcPageResponse.Cookie;
}
while (Convert.ToBoolean(rcPageResponse.Cookie.Length));
}
return hsSearchResult;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
if
&&
=
new
StackFrame(0,
iMinThreads
MAX_DC_POOL_THREADS
CPU_CORE_NO_PER_DC
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
foreach (string sDomainController in this.aDcServers)
{
this.lOpenLdapConnections.Add(this.OpenLdapConnection(sDomainController, this.netCredentials));
OOOO
string
sServerName
=
this.lOpenLdapConnections[this.lOpenLdapConnections.Count-1].SessionOptions.HostName;
string
sBaseDn
=
(this.sBaseSearchDn
==
null
||
this.sBaseSearchDn.Equals(String.Empty))
?
String.Format("DC={0}",
sServerName.Substring(sServerName.IndexOf('.') + 1).Replace(".", ",DC="))
: this.sBaseSearchDn;
Interlocked.Increment(ref iThreadCount);
LdapRequest oLdapRequest = new LdapRequest(
this.lOpenLdapConnections[this.lOpenLdapConnections.Count-1],
LdapFilter,
Attributes,
sBaseDn);
ThreadPool.QueueUserWorkItem(delegate
{
try
{
this.GetDcSpecificAttribute(oLdapRequest);
}
finally
{
if (Interlocked.Decrement(ref iThreadCount) == 0)
{
oManualResetEvent.Set();
}
}
});
}
if (Interlocked.Decrement(ref iThreadCount) == 0)
{
oManualResetEvent.Set();
}
oManualResetEvent.WaitOne();
return this.lResults;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
StackFrame(0,
PPPP
HashSet<string>
hsSearchResult
XtLdap.LdapEngine.UniqueObjectIdentifier.distinguishedName, false);
return
this.FindObjects(LdapFilter,
this.RetrieveTranslatedAttributes(hsSearchResult,
AttributesToLoad,
KeyAttribute);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
finally
{
this.DisposeAllConnections();
}
}
public Dictionary<string, Dictionary<string, string>> FindObjects(HashSet<string> ObjectsCollection,
string ObjectIdAttribute, string[] AttributesToLoad )
{
try
{
this.dicIndexedTranslatedResults = new Dictionary<string, Dictionary<string,
string>>(StringComparer.OrdinalIgnoreCase);
int iThreadCount = 1;
int iMaxThreads;
int iMaxCompletionThreads;
ThreadPool.GetMaxThreads(out iMaxThreads, out iMaxCompletionThreads);
int
iMinThreads
MAX_DC_POOL_THREADS
CPU_CORE_NO_PER_DC
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
this.OpenAllConnections();
IEnumerator<LdapConnection>
this.lOpenLdapConnections.GetEnumerator();
enLdapConnection
QQQQ
});
}
if (Interlocked.Decrement(ref iThreadCount) == 0)
{
oManualResetEvent.Set();
}
oManualResetEvent.WaitOne();
return this.dicIndexedTranslatedResults;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
StackFrame(0,
RRRR
//PAGED
if (this.iPageSize > 0)
{
rcPageRequest = new PageResultRequestControl();
rcPageRequest.PageSize = this.iPageSize;
srRequest.Controls.Add(rcPageRequest);
do
{
dirRes
(SearchResponse)oLdapConnection.SendRequest(srRequest);
rcPageResponse
(PageResultResponseControl)dirRes.Controls[0];
=
=
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
Dictionary<string, object> dicProperties =
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach
(string
sAttribute
in
AttributesToLoad)
{
if
(srEntry.Attributes.Contains(sAttribute))
{
dicProperties.Add(sAttribute,
srEntry.Attributes[sAttribute].GetValues(srEntry.Attributes[sAttribute][0].GetType()));
}
}
yield return dicProperties;
}
}
rcPageRequest.Cookie = rcPageResponse.Cookie;
}
while (Convert.ToBoolean(rcPageResponse.Cookie.Length));
}
//NOT PAGED
else
{
dirRes = (SearchResponse)oLdapConnection.SendRequest(srRequest);
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
Dictionary<string, object> dicProperties = new
Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach (string sAttribute in AttributesToLoad)
{
if (srEntry.Attributes.Contains(sAttribute))
{
dicProperties.Add(sAttribute,
srEntry.Attributes[sAttribute].GetValues(srEntry.Attributes[sAttribute][0].GetType()));
}
}
yield return dicProperties;
}
}
}
//dispose
if (dirRes != null)
if (srRequest != null)
if (rcPageRequest != null)
SSSS
{ dirRes = null; }
{ srRequest = null; }
{ rcPageRequest = null; }
iMinThreads
MAX_DC_POOL_THREADS
CPU_CORE_NO_PER_DC
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
this.OpenAllConnections();
IEnumerator<LdapConnection>
this.lOpenLdapConnections.GetEnumerator();
enLdapConnection
TTTT
{
oManualResetEvent.Set();
}
oManualResetEvent.WaitOne();
return this.dicIndexedResults;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
StackFrame(0,
iMinThreads
MAX_DC_POOL_THREADS
CPU_CORE_NO_PER_DC
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
this.OpenAllConnections();
IEnumerator<LdapConnection>
this.lOpenLdapConnections.GetEnumerator();
enLdapConnection
UUUU
{
enLdapConnection.Reset();
enLdapConnection.MoveNext();
}
LdapRequest oLdapRequest = new LdapRequest(
enLdapConnection.Current,
AttributesToLoad,
sObjectDn,
KeyAttribute);
ThreadPool.QueueUserWorkItem(delegate
{
try
{
this.FastRetrieveTranslatedAttributes(oLdapRequest);
}
finally
{
if (Interlocked.Decrement(ref iThreadCount) == 0)
{
oManualResetEvent.Set();
}
}
});
}
if (Interlocked.Decrement(ref iThreadCount) == 0)
{
oManualResetEvent.Set();
}
oManualResetEvent.WaitOne();
return this.dicIndexedTranslatedResults;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
public
Dictionary<string,
Dictionary<string,
string>>
RetrieveTranslatedUpdatedAttributes(HashSet<string> DistinguishedNameCollection, List<string> AttributesToLoad,
string KeyAttribute)
{
try
{
AttributesToLoad.Add("msDS-ReplAttributeMetaData");
this.dicIndexedTranslatedResults
string>>(StringComparer.OrdinalIgnoreCase);
new
Dictionary<string,
Dictionary<string,
int iThreadCount = 1;
int iMaxThreads;
int iMaxCompletionThreads;
ThreadPool.GetMaxThreads(out iMaxThreads, out iMaxCompletionThreads);
int
iMinThreads
MAX_DC_POOL_THREADS
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
VVVV
CPU_CORE_NO_PER_DC
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
this.OpenAllConnections();
IEnumerator<LdapConnection>
this.lOpenLdapConnections.GetEnumerator();
enLdapConnection
return this.dicIndexedTranslatedResults;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
StackFrame(0,
WWWW
if (this.iHighestCommittedUSN > 0)
{
LdapFilter
=
String.Format(@"(&(uSNChanged>={0})({1}))",
this.iHighestCommittedUSN, LdapFilter);
}
HashSet<string> hsSearchResult = this.FindObjects(LdapFilter, KeyAttribute, true);
return hsSearchResult;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
finally
{
this.DisposeAllConnections();
}
}
new
StackFrame(0,
new
XXXX
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
iMinThreads
MAX_DC_POOL_THREADS
CPU_CORE_NO_PER_DC
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
this.OpenAllConnections();
IEnumerator<LdapConnection>
this.lOpenLdapConnections.GetEnumerator();
enLdapConnection
YYYY
});
}
if (Interlocked.Decrement(ref iThreadCount) == 0)
{
oManualResetEvent.Set();
}
oManualResetEvent.WaitOne();
return this.lResults;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
finally
{
this.DisposeAllConnections();
}
}
public
DistinguishedNameCollection)
{
try
{
Dictionary<string,
HashSet<string>>
new
StackFrame(0,
GetMembers(HashSet<string>
new
ZZZZ
System.DirectoryServices.Protocols.SearchScope.Base,
new string[] { sCurrentRange }
));
if
dirResDet.Entries[0].Attributes.Count > 0)
(dirResDet.Entries.Count
>
&&
{
srEntry = dirResDet.Entries[0];
foreach
(string
sAttr
in
srEntry.Attributes.AttributeNames)
{
foreach
(string
sMemberDn
in
srEntry.Attributes[sAttr].GetValues(Type.GetType("System.String")))
{
dicSearchResult[sGroupDn].Add(sMemberDn);
iIndex++;
}
if (sAttr.IndexOf('*') > 0)
{
bMoreData = false;
}
else
{
iStep
srEntry.Attributes[sAttr].Count;
sCurrentRange
bMoreData = false;
}
}
}
return dicSearchResult;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
finally
{
this.DisposeAllConnections();
}
}
public
Dictionary<string,
Dictionary<string,
MembershipAction>>
GetUpdatedMembers(HashSet<string> DistinguishedNameCollection)
{
try
{
this.dicMshipsActions
=
new
Dictionary<string,
Dictionary<string,
MembershipAction>>(StringComparer.OrdinalIgnoreCase);
int iThreadCount = 1;
int iMaxThreads;
int iMaxCompletionThreads;
ThreadPool.GetMaxThreads(out iMaxThreads, out iMaxCompletionThreads);
AAAAA
iMinThreads
MAX_DC_POOL_THREADS
CPU_CORE_NO_PER_DC
this.aDcServers.Length;
if (iMinThreads >= iMaxThreads)
{
iMinThreads = iMaxThreads - 1;
}
ThreadPool.SetMinThreads(iMinThreads, iMinThreads);
ManualResetEvent oManualResetEvent = new ManualResetEvent(false);
this.OpenAllConnections();
IEnumerator<LdapConnection>
this.lOpenLdapConnections.GetEnumerator();
enLdapConnection
return this.dicMshipsActions;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
#endregion
BBBBB
new
StackFrame(0,
new
|
dirRes = (SearchResponse)oLdapRequest.ldapConnection.SendRequest(srRequest);
if (dirRes.Entries.Count > 0)
{
srEntry = dirRes.Entries[0];
string sKeyValue = null;
if
(srEntry.Attributes.Contains(oLdapRequest.KeyAttribute)
&&
dicAttributeList.ContainsKey(oLdapRequest.KeyAttribute) && dicAttributeList[oLdapRequest.KeyAttribute].Equals("Sid",
StringComparison.OrdinalIgnoreCase))
{
object[]
aValues
=
srEntry.Attributes[oLdapRequest.KeyAttribute].GetValues(Type.GetType("System.Byte[]"));
sKeyValue
=
(new
SecurityIdentifier((byte[])aValues[0],
0)).ToString();
}
else if (srEntry.Attributes.Contains(oLdapRequest.KeyAttribute) &&
dicAttributeList.ContainsKey(oLdapRequest.KeyAttribute)
&&
dicAttributeList[oLdapRequest.KeyAttribute].Equals("Unicode", StringComparison.OrdinalIgnoreCase))
{
sKeyValue
=
srEntry.Attributes[oLdapRequest.KeyAttribute][0].ToString();
}
else if (srEntry.Attributes.Contains(oLdapRequest.KeyAttribute) &&
dicAttributeList.ContainsKey(oLdapRequest.KeyAttribute)
&&
dicAttributeList[oLdapRequest.KeyAttribute].Equals("String", StringComparison.OrdinalIgnoreCase))
{
sKeyValue
=
srEntry.Attributes[oLdapRequest.KeyAttribute][0].ToString();
}
else if (srEntry.Attributes.Contains(oLdapRequest.KeyAttribute) &&
dicAttributeList.ContainsKey(oLdapRequest.KeyAttribute)
&&
dicAttributeList[oLdapRequest.KeyAttribute].Equals("IString", StringComparison.OrdinalIgnoreCase))
{
sKeyValue
=
srEntry.Attributes[oLdapRequest.KeyAttribute][0].ToString();
}
CCCCC
(string
sAccRuleName
in
oLdapRequest.AttributesToLoad)
{
try
{
if
(sAccRuleName.Equals("IdentityReference", StringComparison.OrdinalIgnoreCase))
{
if
(accRule.IdentityReference.IsValidTargetType(typeof(NTAccount)))
{
dicTrusteeRights.Add(sAccRuleName, accRule.IdentityReference.Value);
}
else
{
try
{
dicTrusteeRights.Add(sAccRuleName,
accRule.IdentityReference.Translate(typeof(System.Security.Principal.NTAccount)).Value);
}
catch
{
dicTrusteeRights.Add(sAccRuleName, accRule.IdentityReference.Value);
}
}
else
(sAccRuleName.Equals("AccessControlType", StringComparison.OrdinalIgnoreCase))
DDDDD
}
if
dicTrusteeRights.Add(sAccRuleName, accRule.AccessControlType.ToString());
}
else
(sAccRuleName.Equals("ActiveDirectoryRights", StringComparison.OrdinalIgnoreCase))
{
if
dicTrusteeRights.Add(sAccRuleName, accRule.ActiveDirectoryRights.ToString());
}
else
(sAccRuleName.Equals("InheritanceFlags", StringComparison.OrdinalIgnoreCase))
{
if
dicTrusteeRights.Add(sAccRuleName, accRule.InheritanceFlags.ToString());
}
else
if
(sAccRuleName.Equals("InheritanceType", StringComparison.OrdinalIgnoreCase))
{
dicTrusteeRights.Add(sAccRuleName, accRule.InheritanceType.ToString());
}
else
if
(sAccRuleName.Equals("IsInherited", StringComparison.OrdinalIgnoreCase))
{
dicTrusteeRights.Add(sAccRuleName, accRule.IsInherited.ToString());
}
else
if
(sAccRuleName.Equals("InheritedObjectType", StringComparison.OrdinalIgnoreCase)
&&
Convert.ToBoolean(ObjectAceFlags.InheritedObjectAceTypePresent & accRule.ObjectFlags))
{
string
sInheritedObjectType = accRule.InheritedObjectType.ToString();
dicTrusteeRights.Add(sAccRuleName, this.dicExtAccessRights.ContainsKey(sInheritedObjectType)
? this.dicExtAccessRights[sInheritedObjectType]
: sInheritedObjectType);
}
else
(sAccRuleName.Equals("ObjectType", StringComparison.OrdinalIgnoreCase)
if
&&
sObjectType
accRule.ObjectType.ToString();
dicTrusteeRights.Add(sAccRuleName, this.dicExtAccessRights.ContainsKey(sObjectType)
? this.dicExtAccessRights[sObjectType]
: sObjectType);
}
}
catch
{
}
}
}
}
}
EEEEE
}
this.AddObjectToList(dicTrusteeRights);
string>
dicProperties
new
Dictionary<string,
new
dirRes = (SearchResponse)oLdapRequest.ldapConnection.SendRequest(srRequest);
string sServerName = oLdapRequest.ldapConnection.SessionOptions.HostName;
string sDomainFqdn = sServerName.Substring(sServerName.IndexOf('.') + 1);
if (dirRes.Entries.Count > 0)
{
srEntry = dirRes.Entries[0];
foreach (string sAttribute in oLdapRequest.AttributesToLoad)
{
string sValue = null;
if
(sAttribute.Equals("memberOf",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains(sAttribute))
{
foreach
(string
sGroupDN
in
srEntry.Attributes[sAttribute].GetValues(Type.GetType("System.String")))
{
{
sValue += String.Format("|{0}",
sGroupDN);
}
sValue = sValue.TrimStart('|');
}
}
else
if
(sAttribute.Equals("Domain",
StringComparison.OrdinalIgnoreCase))
{
sValue = sDomainFqdn;
}
else
if
(sAttribute.Equals("Path",
StringComparison.OrdinalIgnoreCase) )
{
FFFFF
String.Format(@"LDAP://{0}",
oLdapRequest.AttributeValue );
}
else
if
(sAttribute.Equals("AdsPath",
StringComparison.OrdinalIgnoreCase) )
{
sValue
oLdapRequest.AttributeValue );
String.Format(@"LDAP://{0}",
}
else
if
(sAttribute.StartsWith("UAC_",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains("userAccountControl"))
{
UserAccountControl
enUAC
=
(UserAccountControl)Enum.Parse(typeof(UserAccountControl), sAttribute.ToUpper());
if
(Convert.ToBoolean(Convert.ToInt32(srEntry.Attributes["userAccountControl"][0]) & ((int)enUAC)))
{
sValue = "1";
}
else
{
sValue = "0";
}
}
else
if
(sAttribute.Equals("selective_authentication",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains("ntSecurityDescriptor"))
{
object[]
aValues
=
srEntry.Attributes["ntSecurityDescriptor"].GetValues(Type.GetType("System.Byte[]"));
string
sSecurityDescriptorSDDL
=
this.GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections.Access, (byte[])aValues[0]);
if
(sSecurityDescriptorSDDL.Contains("(OA;;CR;68b1d179-0d15-4d4f-ab71-46152e79a7bc;;S-1-5-1000)"))
{
sValue = "1";
}
else
{
sValue = "0";
}
}
else
if
(sAttribute.Equals("ntSecurityDescriptor",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains(sAttribute))
{
object[]
aValues
=
srEntry.Attributes["ntSecurityDescriptor"].GetValues(Type.GetType("System.Byte[]"));
sValue
=
this.GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections.Owner, (byte[])aValues[0]);
int i = sValue.Length;
}
else
if
(sAttribute.StartsWith("TSL_",
StringComparison.OrdinalIgnoreCase)
&&
srEntry.Attributes.Contains(sAttribute.Substring(4))
&&
dicAttributeList[sAttribute.Substring(4)].Equals("Sid", StringComparison.OrdinalIgnoreCase))
{
//object[]
aValues
=
srEntry.Attributes[sAttribute.Substring(4)].GetValues(Type.GetType("System.Byte[]") );
//for (int i = 0; i < aValues.Length; i++)
//{
// string s = null;
// string x = null;
// try
// {
//
SecurityIdentifier oSID = new
SecurityIdentifier((byte[])aValues[i], 0);
GGGGG
s = oSID.ToString();
x
(oSID).Translate(typeof(NTAccount)).Value.ToString();
//
//sValue = String.Format("{0}|",
// }
// catch
// {
// }
//}
//sValue = sValue.TrimEnd('|');
}
//ALL OTHER ATTRIBUTES
else
if
(srEntry.Attributes.Contains(sAttribute)
&&
dicAttributeList.ContainsKey(sAttribute) )
{
sValue
this.TranslateAtribute(srEntry.Attributes[sAttribute]);
}
dicProperties.Add(sAttribute, sValue);
}
string sKeyValue;
if (dicProperties.TryGetValue(oLdapRequest.KeyAttribute, out sKeyValue))
{
this.AddTranslatedObjectToDictionary(sKeyValue,
dicProperties);
}
}
}
catch (Exception ex)
{
EventLog oEventLog = new System.Diagnostics.EventLog("Application", ".",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
oEventLog.WriteEntry(String.Format("{0}::{1}",
new
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message), EventLogEntryType.Error, 6666);
oEventLog.Dispose();
}
}
private void RetrieveTranslatedAttributes(object oLdapRqst)
{
try
{
SearchResponse dirRes = null;
SearchRequest srRequest = null;
SearchResultEntry srEntry = null;
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
string>
dicProperties
new
Dictionary<string,
HHHHH
}
else
{
srRequest = new SearchRequest(
sDomainDn,
sFilter,
System.DirectoryServices.Protocols.SearchScope.Subtree,
oLdapRequest.AttributesToLoad
);
}
dirRes = (SearchResponse)oLdapRequest.ldapConnection.SendRequest(srRequest);
if (dirRes.Entries.Count > 0)
{
srEntry = dirRes.Entries[0];
foreach (string sAttribute in oLdapRequest.AttributesToLoad)
{
string sValue = null;
if
(sAttribute.Equals("memberOf",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains(sAttribute))
{
foreach
(string
sGroupDN
in
srEntry.Attributes[sAttribute].GetValues(Type.GetType("System.String")))
{
{
sValue += String.Format("|{0}",
sGroupDN);
}
sValue = sValue.TrimStart('|');
}
}
else
if
(sAttribute.Equals("Domain",
StringComparison.OrdinalIgnoreCase))
{
sValue = sDomainFqdn;
}
else
if
(sAttribute.Equals("Path",
StringComparison.OrdinalIgnoreCase))
{
sValue
=
String.Format(@"LDAP://{0}",
oLdapRequest.DistinguishedName);
}
else
if
(sAttribute.Equals("AdsPath",
StringComparison.OrdinalIgnoreCase))
{
sValue
=
String.Format(@"LDAP://{0}",
oLdapRequest.DistinguishedName);
}
else
if
(sAttribute.StartsWith("UAC_",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains("userAccountControl"))
{
UserAccountControl
enUAC
=
(UserAccountControl)Enum.Parse(typeof(UserAccountControl), sAttribute.ToUpper());
if
(Convert.ToBoolean(Convert.ToInt32(srEntry.Attributes["userAccountControl"][0]) & ((int)enUAC)))
{
sValue = "1";
}
else
{
IIIII
}
else
if
(sAttribute.Equals("selective_authentication",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains("ntSecurityDescriptor"))
{
object[]
aValues
=
srEntry.Attributes["ntSecurityDescriptor"].GetValues(Type.GetType("System.Byte[]"));
string
sSecurityDescriptorSDDL
=
this.GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections.Access, (byte[])aValues[0]);
if
(sSecurityDescriptorSDDL.Contains("(OA;;CR;68b1d179-0d15-4d4f-ab71-46152e79a7bc;;S-1-5-1000)"))
{
sValue = "1";
}
else
{
sValue = "0";
}
}
else
if
(sAttribute.Equals("ntSecurityDescriptor",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains(sAttribute))
{
object[]
aValues
=
srEntry.Attributes["ntSecurityDescriptor"].GetValues(Type.GetType("System.Byte[]"));
sValue
=
this.GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections.Owner, (byte[])aValues[0]);
int i = sValue.Length;
}
else
if
(sAttribute.StartsWith("TSL_",
StringComparison.OrdinalIgnoreCase)
&&
srEntry.Attributes.Contains(sAttribute.Substring(4))
&&
dicAttributeList[sAttribute.Substring(4)].Equals("Sid", StringComparison.OrdinalIgnoreCase))
{
//object[]
aValues
=
srEntry.Attributes[sAttribute.Substring(4)].GetValues(Type.GetType("System.Byte[]") );
}
//ALL OTHER ATTRIBUTES
else
if
(srEntry.Attributes.Contains(sAttribute)
&&
dicAttributeList.ContainsKey(sAttribute))
{
sValue
this.TranslateAtribute(srEntry.Attributes[sAttribute]);
}
dicProperties.Add(sAttribute, sValue);
}
this.AddTranslatedObjectToDictionary(oLdapRequest.AttributeValue,
dicProperties);
}
}
catch (Exception ex)
{
EventLog oEventLog = new System.Diagnostics.EventLog("Application", ".",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
oEventLog.WriteEntry(String.Format("{0}::{1}",
new
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message), EventLogEntryType.Error, 6666);
oEventLog.Dispose();
}
}
private void RetrieveAttributes(object oLdapRqst)
{
try
JJJJJ
{
SearchResponse dirRes = null;
SearchRequest srRequest = null;
SearchResultEntry srEntry = null;
Dictionary<string,
object>(StringComparer.OrdinalIgnoreCase);
object>
dicProperties
new
Dictionary<string,
KKKKK
}
}
private void FastRetrieveTranslatedUpdatedAttributes(object oLdapRqst)
{
try
{
const int RETRY_NO = 10;
SearchResponse dirRes = null;
SearchRequest srRequest = null;
SearchResultEntry srEntry = null;
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
string>
dicProperties
new
Dictionary<string,
new
dirRes
=
(SearchResponse)oLdapRequest.ldapConnection.SendRequest(srRequest);
bRetry = false;
}
catch (DirectoryOperationException ex)
{
if (iTries % RETRY_NO == 0)
{
bRetry = false;
throw new Exception(string.Format("{0}::{1}", new
StackFrame(0, true).GetMethod().Name, ex.Message));
}
else
{
bRetry = true;
}
}
} while (bRetry);
string sServerName = oLdapRequest.ldapConnection.SessionOptions.HostName;
string sDomainFqdn = sServerName.Substring(sServerName.IndexOf('.') + 1);
if (dirRes.Entries.Count > 0)
{
HashSet<string>
HashSet<string>(StringComparer.OrdinalIgnoreCase);
hsUpdatedAttributes
srEntry = dirRes.Entries[0];
if (srEntry.Attributes.Contains("msDS-ReplAttributeMetaData"))
{
LLLLL
new
foreach
(object
oValue
in
srEntry.Attributes["msDSReplAttributeMetaData"].GetValues(Type.GetType("System.String")))
{
Dictionary<string, string> dicAttributeReplData =
GetNodesInnertext(oValue.ToString(), new string[] { "pszAttributeName", "usnLocalChange" }, true);
if
(Convert.ToInt64(dicAttributeReplData["usnLocalChange"]) > this.iHighestCommittedUSN)
{
hsUpdatedAttributes.Add(dicAttributeReplData["pszAttributeName"]);
hsUpdatedAttributes.Add("whenChanged");
if
(dicAttributeReplData["pszAttributeName"].Equals("Name", StringComparison.OrdinalIgnoreCase))
{
hsUpdatedAttributes.Add("DistinguishedName");
hsUpdatedAttributes.Add("Path");
}
else
if
(dicAttributeReplData["pszAttributeName"].Equals("userAccountControl", StringComparison.OrdinalIgnoreCase))
{
foreach (UserAccountControl enUAC
in Enum.GetValues(typeof(UserAccountControl)))
{
hsUpdatedAttributes.Add(enUAC.ToString());
}
}
else
(dicAttributeReplData["pszAttributeName"].Equals("ntSecurityDescriptor", StringComparison.OrdinalIgnoreCase))
{
if
hsUpdatedAttributes.Add("selective_authentication");
}
}
}
foreach (string sAttribute in oLdapRequest.AttributesToLoad)
{
if
(hsUpdatedAttributes.Contains(sAttribute)
||
sAttribute.Equals(oLdapRequest.KeyAttribute, StringComparison.OrdinalIgnoreCase))
{
string sValue = null;
if
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains(sAttribute))
{
(sAttribute.Equals("memberOf",
foreach
(string
sGroupDN
in
srEntry.Attributes[sAttribute].GetValues(Type.GetType("System.String")))
{
{
sValue
+=
String.Format("|{0}", sGroupDN);
}
sValue
sValue.TrimStart('|');
}
}
else
StringComparison.OrdinalIgnoreCase))
if
(sAttribute.Equals("Domain",
{
sValue = sDomainFqdn;
}
MMMMM
if
(sAttribute.Equals("Path",
StringComparison.OrdinalIgnoreCase))
{
sValue
String.Format(@"LDAP://{0}", oLdapRequest.AttributeValue);
}
else
StringComparison.OrdinalIgnoreCase))
if
(sAttribute.Equals("AdsPath",
{
sValue
String.Format(@"LDAP://{0}", oLdapRequest.AttributeValue);
}
else
if
(sAttribute.StartsWith("UAC_",
StringComparison.OrdinalIgnoreCase) && srEntry.Attributes.Contains("userAccountControl"))
{
UserAccountControl
enUAC
=
(UserAccountControl)Enum.Parse(typeof(UserAccountControl), sAttribute.ToUpper());
if
(Convert.ToBoolean(Convert.ToInt32(srEntry.Attributes["userAccountControl"][0]) & ((int)enUAC)))
{
sValue = "1";
}
else
{
sValue = "0";
}
}
else
if
(sAttribute.Equals("selective_authentication",
StringComparison.OrdinalIgnoreCase)
&&
srEntry.Attributes.Contains("ntSecurityDescriptor"))
{
object[]
aValues
=
srEntry.Attributes["ntSecurityDescriptor"].GetValues(Type.GetType("System.Byte[]"));
string sSecurityDescriptorSDDL =
this.GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections.Access, (byte[])aValues[0]);
if
(sSecurityDescriptorSDDL.Contains("(OA;;CR;68b1d179-0d15-4d4f-ab71-46152e79a7bc;;S-1-5-1000)"))
{
sValue = "1";
}
else
{
sValue = "0";
}
}
else
if
(sAttribute.Equals("ntSecurityDescriptor",
StringComparison.OrdinalIgnoreCase)
&&
srEntry.Attributes.Contains(sAttribute))
{
object[]
aValues
=
srEntry.Attributes["ntSecurityDescriptor"].GetValues(Type.GetType("System.Byte[]"));
sValue
=
this.GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections.Owner, (byte[])aValues[0]);
int i = sValue.Length;
}
else
if
(sAttribute.StartsWith("TSL_",
StringComparison.OrdinalIgnoreCase)
&&
srEntry.Attributes.Contains(sAttribute.Substring(4))
&&
dicAttributeList[sAttribute.Substring(4)].Equals("Sid", StringComparison.OrdinalIgnoreCase))
{
}
//ALL OTHER ATTRIBUTES
else
if
(srEntry.Attributes.Contains(sAttribute) && dicAttributeList.ContainsKey(sAttribute))
{
NNNNN
this.TranslateAtribute(srEntry.Attributes[sAttribute]);
}
if
(sAttribute.Equals(oLdapRequest.KeyAttribute, StringComparison.OrdinalIgnoreCase))
{
oLdapRequest.AttributeValue
sValue;
}
else
{
dicProperties.Add(sAttribute,
sValue);
}
}
}
if (dicProperties.Count > 0)
{
this.AddTranslatedObjectToDictionary(oLdapRequest.AttributeValue, dicProperties);
}
}
}
}
catch (Exception ex)
{
EventLog oEventLog = new System.Diagnostics.EventLog("Application", ".",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
oEventLog.WriteEntry(String.Format("{0}::{1}",
new
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message), EventLogEntryType.Error, 6663);
oEventLog.Dispose();
}
}
private void GetDcSpecificAttribute(object oLdapRqst)
{
Dictionary<string, string> dicSearchResult = null;
try
{
SearchResponse dirRes = null;
SearchRequest srRequest = null;
PageResultRequestControl rcPageRequest = null;
PageResultResponseControl rcPageResponse = null;
LdapRequest oLdapRequest = (LdapRequest)oLdapRqst;
string sServerName = oLdapRequest.ldapConnection.SessionOptions.HostName;
string sDomainFqdn = sServerName.Substring(sServerName.IndexOf('.') + 1);
srRequest = new SearchRequest(
oLdapRequest.AttributeValue,
oLdapRequest.LdapFilter,
System.DirectoryServices.Protocols.SearchScope.Subtree,
oLdapRequest.AttributesToLoad
);
rcPageRequest = new PageResultRequestControl();
rcPageRequest.PageSize = this.iPageSize;
srRequest.Controls.Add(rcPageRequest);
do
OOOOO
{
dirRes
(SearchResponse)oLdapRequest.ldapConnection.SendRequest(srRequest);
rcPageResponse = (PageResultResponseControl)dirRes.Controls[0];
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
dicSearchResult
=
new
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
foreach
(string
sAttribute
in
oLdapRequest.AttributesToLoad)
{
string sValue = null;
if
(sAttribute.Equals("logonDomain",
StringComparison.OrdinalIgnoreCase))
{
sValue = sDomainFqdn;
}
else
StringComparison.OrdinalIgnoreCase))
if
(sAttribute.Equals("logonServer",
{
sValue = sServerName;
}
else
(srEntry.Attributes.Contains(sAttribute) && dicAttributeList.ContainsKey(sAttribute))
{
if
sValue
this.TranslateAtribute(srEntry.Attributes[sAttribute]);
}
dicSearchResult.Add(sAttribute, sValue);
}
this.AddObjectToList(dicSearchResult);
}
}
rcPageRequest.Cookie = rcPageResponse.Cookie;
}
while (Convert.ToBoolean(rcPageResponse.Cookie.Length));
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
(SearchResponse)oLdapRequest.ldapConnection.SendRequest(new
SearchRequest(
oLdapRequest.AttributeValue,
String.Format("(&{0}(member=*))", sGroupFilter),
System.DirectoryServices.Protocols.SearchScope.Base,
"member","objectSid"
PPPPP
));
if (dirRes.Entries.Count > 0)
{
object[] aValues = null;
SecurityIdentifier oSID = null;
srEntry = dirRes.Entries[0];
aValues
srEntry.Attributes["objectSid"].GetValues(Type.GetType("System.Byte[]"));
oSID = new SecurityIdentifier((byte[])aValues[0], 0);
=
=
new
lMembers.Add(oSID.ToString());
}
}
}
this.AddMshipsToDictionary(sObjectSid, lMembers);
}
}
catch (Exception ex)
{
EventLog oEventLog = new System.Diagnostics.EventLog("Application", ".",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
oEventLog.WriteEntry(String.Format("{0}::{1}",
new
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message), EventLogEntryType.Error, 6666);
oEventLog.Dispose();
}
}
private void FastRetrieveUpdatedMembers(object oLdapRqst)
{
try
{
const ushort RETRY_NO = 10;
SearchResponse dirRes = null;
SearchRequest srRequest = null;
SearchResultEntry srEntry = null;
LdapRequest oLdapRequest = (LdapRequest)oLdapRqst;
QQQQQ
Dictionary<string, MembershipAction>
MembershipAction>(StringComparer.OrdinalIgnoreCase);
dicActions
new
Dictionary<string,
//SecurityDescriptorFlagControl
sdControl
=
SecurityDescriptorFlagControl(System.DirectoryServices.Protocols.SecurityMasks.Dacl);
//ResultCode.bu
string sAttribute = "msDS-ReplValueMetaData";
string sRange = String.Format(@"{0};range={{0}}-{{1}}", sAttribute);
new
int iIndex = 0;
int iStep = 0;
string sCurrentRange = String.Format(sRange, iIndex, '*');
bool bMoreData = true;
while (bMoreData)
{
ushort iTries = 0;
bool bRetry = false;
do
{
try
{
iTries++;
srRequest = new SearchRequest(
oLdapRequest.AttributeValue,
@"(&(objectClass=group)(objectCategory=group))",
System.DirectoryServices.Protocols.SearchScope.Base,
new string[] { sCurrentRange }
);
dirRes
(SearchResponse)oLdapRequest.ldapConnection.SendRequest(srRequest);
bRetry = false;
}
catch (DirectoryOperationException ex)
{
if (iTries % RETRY_NO == 0)
{
bRetry = false;
throw
Exception(string.Format("{0}::{1}", new StackFrame(0, true).GetMethod().Name, ex.Message));
}
else
{
bRetry = true;
}
}
} while (bRetry);
new
RRRRR
if
(dicAttributeReplData["ftimeDeleted"].Equals("1601-01-01T00:00:00Z", StringComparison.OrdinalIgnoreCase))
{
dicActions.Add(dicAttributeReplData["pszObjectDn"], MembershipAction.Add);
}
else
{
dicActions.Add(dicAttributeReplData["pszObjectDn"], MembershipAction.Remove);
}
}
}
iIndex++;
}
if (sAttr.IndexOf('*') > 0)
{
bMoreData = false;
}
else
{
iStep = srEntry.Attributes[sAttr].Count;
sCurrentRange = String.Format(sRange,
iIndex, iIndex + iStep);
}
}
else
{
bMoreData = false;
}
}
if (dicActions.Count > 0)
{
this.AddMshipActionsToDictionary(oLdapRequest.AttributeValue,
dicActions);
}
}
catch (Exception ex)
{
EventLog oEventLog = new System.Diagnostics.EventLog("Application", ".",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
oEventLog.WriteEntry(String.Format("{0}::{1}",
new
StackTrace(true).GetFrame(0).GetMethod().Name.ToString(), ex.Message), EventLogEntryType.Error, 6663);
oEventLog.Dispose();
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
private void AddObjectToList(Dictionary<string, string> dicObjectDetails)
{
try
{
this.lResults.Add(dicObjectDetails);
}
catch (Exception ex)
SSSSS
{
throw
true).GetMethod().Name, ex.Message));
}
}
new
Exception(string.Format("{0}::{1}",
[MethodImpl(MethodImplOptions.Synchronized)]
private void AddGenObjectToList(Dictionary<string, object> dicObjectDetails)
{
try
{
this.lGenResults.Add(dicObjectDetails);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
}
new
StackFrame(0,
new
StackFrame(0,
[MethodImpl(MethodImplOptions.Synchronized)]
private void AddTranslatedObjectToDictionary(string sKey, Dictionary<string, string> dicObjectDetails)
{
try
{
if (!dicIndexedTranslatedResults.ContainsKey(sKey))
{
this.dicIndexedTranslatedResults.Add(sKey, dicObjectDetails);
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
private void AddObjectToDictionary(string sKey, Dictionary<string, object> dicObjectDetails)
{
try
{
if (!this.dicIndexedResults.ContainsKey(sKey))
{
this.dicIndexedResults.Add(sKey, dicObjectDetails);
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
private void AddMshipsToDictionary(string sGroupSid, List<string> lMemberSids)
{
try
{
if (!this.dicMshipsResults.ContainsKey(sGroupSid))
{
this.dicMshipsResults.Add(sGroupSid, lMemberSids);
}
}
catch (Exception ex)
{
TTTTT
dicActions)
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
[MethodImpl(MethodImplOptions.Synchronized)]
private void AddMshipActionsToDictionary(string sGroupDn, Dictionary<string, MembershipAction>
{
try
{
if (!this.dicMshipsActions.ContainsKey(sGroupDn))
{
this.dicMshipsActions.Add(sGroupDn, dicActions);
}
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
}
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
oLdapConnection
new
new
LdapConnection(oLdapDirectory,
netCred, AuthType.Basic);
LdapConnection oLdapConnection = new LdapConnection(oLdapDirectory, netCred);
oLdapConnection.Bind();
oLdapConnection.Timeout = TimeSpan.FromSeconds(CONN_TIME_OUT);
oLdapConnection.SessionOptions.TcpKeepAlive = true;
oLdapConnection.SessionOptions.ProtocolVersion = 3;
//prevents ldap connection from connecting to other servers during session
oLdapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
oLdapConnection.AutoBind = false;
return oLdapConnection;
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void OpenAllConnections()
{
try
{
this.lOpenLdapConnections = new List<LdapConnection>();
for (int i = 0; i < NUMBER_OF_OPEN_TCP_CONNECTIONS; i++)
{
foreach (string sDC in this.aDcServers)
{
try
{
LdapDirectoryIdentifier oLdapDirectory = new
LdapDirectoryIdentifier(sDC, 389);
UUUUU
oLdapConnection
(this.netCredentials == null)
?
new
new
LdapConnection(oLdapDirectory)
LdapConnection(oLdapDirectory, netCredentials);
oLdapConnection.Timeout
TimeSpan.FromSeconds(CONN_TIME_OUT);
oLdapConnection.SessionOptions.TcpKeepAlive = true;
oLdapConnection.SessionOptions.ProtocolVersion = 3;
oLdapConnection.SessionOptions.ReferralChasing
ReferralChasingOptions.None;
oLdapConnection.AutoBind = false;
oLdapConnection.Bind();
this.lOpenLdapConnections.Add(oLdapConnection);
}
catch
{
}
}
}
if (!(this.lOpenLdapConnections.Count > 0))
{
throw new Exception(string.Format("{0}::{1}", new StackFrame(0,
true).GetMethod().Name, "Couldn't establish any LDAP connection with Domain Controlers"));
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void DisposeAllConnections()
{
try
{
if (this.lOpenLdapConnections != null)
{
foreach (LdapConnection ldapConn in this.lOpenLdapConnections)
{
ldapConn.Dispose();
}
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void LoadLdapAttributes()
{
try
{
using
(LdapConnection
oLdapConnection
this.OpenLdapConnection(this.aDcServers[0], this.netCredentials))
{
SearchResponse dirRes = null;
SearchRequest srRequest = null;
PageResultRequestControl rcPageRequest = null;
VVVVV
new
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
Dictionary<string, Dictionary<string, string>> dicAttributeMappings = new
Dictionary<string, Dictionary<string, string>>(){
{"2.5.5.1",
new
Dictionary<string,string>(){{"127",
"DN-Binary"}}},
{"2.5.5.2",
new
Dictionary<string,string>(){{"6",
"Object-Identifier"}}},
{"2.5.5.3",
new
Dictionary<string,string>(){{"27",
"String"}}},
{"2.5.5.4",
new
Dictionary<string,string>(){{"20",
"IString"}}},
{"2.5.5.5",
new
Dictionary<string,string>(){{"19",
"Printable"}, {"22", "IA5"}}},
{"2.5.5.6",
new
Dictionary<string,string>(){{"18",
"Numeric"}}},
{"2.5.5.7",
new
Dictionary<string,string>(){{"127",
"Object"}}},
{"2.5.5.8",
new
Dictionary<string,string>(){{"1",
"Boolean"}}},
{"2.5.5.9",
new
Dictionary<string,string>(){{"2",
"Integer"}, {"10", "Enumeration"}}},
{"2.5.5.10",
new Dictionary<string,string>(){{"4", "Octet"}}},
{"2.5.5.11",
new Dictionary<string,string>(){{"23",
"UTCTime"}, {"24",
"Generalized-Time"}}},
{"2.5.5.12",
new
Dictionary<string,string>(){{"64",
"Unicode"}}},
{"2.5.5.13",
new
Dictionary<string,string>(){{"127",
"Presentation-Address"}}},
{"2.5.5.14",
new
Dictionary<string,string>(){{"127",
"Object"}}},
{"2.5.5.15",
new Dictionary<string,string>(){{"66",
"NTSec-Desc"}}},
{"2.5.5.16",
new
Dictionary<string,string>(){{"65",
"LargeInteger"}}},
{"2.5.5.17",
new Dictionary<string,string>(){{"4", "Sid"}}}
};
string
@"(&(objectClass=attributeSchema)(oMSyntax=*)(attributeSyntax=*))";
sAttributesFilter
(SearchResponse)oLdapConnection.SendRequest(new
SearchRequest(
null,
"(schemaNamingContext=*)",
System.DirectoryServices.Protocols.SearchScope.Base,
"schemaNamingContext"
));
string
dirRes.Entries[0].Attributes["schemaNamingContext"][0].ToString();
sConfPartDN
WWWWW
"LdapDisplayName" }
);
rcPageRequest = new PageResultRequestControl();
rcPageRequest.PageSize = this.iPageSize;
srRequest.Controls.Add(rcPageRequest);
do
{
dirRes
(SearchResponse)oLdapConnection.SendRequest(srRequest);
rcPageResponse
(PageResultResponseControl)dirRes.Controls[0];
=
=
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
string
sAttributeStx
=
srEntry.Attributes["attributeSyntax"][0].ToString();
string
sAttributeoMStx
srEntry.Attributes["oMSyntax"][0].ToString();
if
(dicAttributeMappings.ContainsKey(sAttributeStx))
{
if
(dicAttributeMappings[sAttributeStx].ContainsKey(sAttributeoMStx))
{
string sAttributeType =
dicAttributeMappings[sAttributeStx][sAttributeoMStx];
string sAttributeName =
srEntry.Attributes["LdapDisplayName"][0].ToString();
dicAttributeList.Add(sAttributeName, sAttributeType);
}
}
}
}
rcPageRequest.Cookie = rcPageResponse.Cookie;
}
while (Convert.ToBoolean(rcPageResponse.Cookie.Length));
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private void LoadExtendedRights()
{
try
{
using
(LdapConnection
oLdapConnection
=
this.OpenLdapConnection(this.aDcServers[0], this.netCredentials))
{
SearchResponse dirRes = null;
SearchRequest srRequest = null;
PageResultRequestControl rcPageRequest = null;
PageResultResponseControl rcPageResponse = null;
dicExtAccessRights
string>(StringComparer.OrdinalIgnoreCase);
XXXXX
new
Dictionary<string,
(SearchResponse)oLdapConnection.SendRequest(new
SearchRequest(
null,
sAttributesFilter,
System.DirectoryServices.Protocols.SearchScope.Base,
"configurationNamingContext"
));
string
dirRes.Entries[0].Attributes["configurationNamingContext"][0].ToString();
sConfPartDN
=
=
if (dirRes.Entries.Count > 0)
{
foreach (SearchResultEntry srEntry in dirRes.Entries)
{
string
sObjectCN
=
srEntry.Attributes["cn"][0].ToString();
Guid
oObjectGuid
Guid((byte[])srEntry.Attributes["objectGUID"].GetValues(Type.GetType("System.Byte[]"))[0]);
new
this.dicExtAccessRights.Add(oObjectGuid.ToString(), sObjectCN);
}
}
rcPageRequest.Cookie = rcPageResponse.Cookie;
}
while (Convert.ToBoolean(rcPageResponse.Cookie.Length));
}
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
#endregion
#region Helper Private Methods
private string TranslateAtribute(DirectoryAttribute daProperty)
{
YYYYY
try
{
string sValue = null;
Type tpAttribute = daProperty[0].GetType();
if
(this.dicAttributeList.ContainsKey(daProperty.Name)
&&
this.dicAttributeList[daProperty.Name].Equals("Sid", StringComparison.OrdinalIgnoreCase))
{
object[] aValues = daProperty.GetValues(Type.GetType("System.Byte[]"));
for (int i = 0; i < aValues.Length; i++)
{
sValue
+=
String.Format("|{0}",
(new
SecurityIdentifier((byte[])aValues[i], 0)).ToString());
}
sValue = sValue.TrimStart('|');
}
else
if
(this.dicAttributeList.ContainsKey(daProperty.Name)
&&
this.dicAttributeList[daProperty.Name].Equals("Octet", StringComparison.OrdinalIgnoreCase))
{
object[] aValues = daProperty.GetValues(Type.GetType("System.Byte[]"));
sValue = new Guid((byte[])aValues[0]).ToString();
}
else
if
(this.dicAttributeList.ContainsKey(daProperty.Name)
this.dicAttributeList[daProperty.Name].Equals("LargeInteger", StringComparison.OrdinalIgnoreCase))
{
Int64 lVal = Convert.ToInt64(daProperty[0]);
if (lVal > 0)
{
sValue
String.Format("{0:yyyy-MM-dd
&&
hh:mm:ss}",
DateTime.FromFileTime(lVal));
}
}
else
if
(this.dicAttributeList.ContainsKey(daProperty.Name)
&&
this.dicAttributeList[daProperty.Name].Equals("Generalized-Time", StringComparison.OrdinalIgnoreCase))
{
if (daProperty[0] != null)
{
sValue
=
String.Format("{0:yyyy-MM-dd
HH:mm:ss}",
DateTime.ParseExact(daProperty[0].ToString(), @"yyyyMMddHHmmss.f'Z'", null));
}
}
else if (Type.GetTypeCode(tpAttribute) == TypeCode.Boolean)
{
object[] aValues = daProperty.GetValues(tpAttribute);
sValue = String.Format("{0}", aValues[0]);
}
else
if
(Type.GetTypeCode(tpAttribute)
==
TypeCode.Int32
||
Type.GetTypeCode(tpAttribute) == TypeCode.Int16)
{
object[] aValues = daProperty.GetValues(tpAttribute);
sValue = String.Format("{0}", aValues[0]);
}
else if (Type.GetTypeCode(tpAttribute) == TypeCode.String)
{
object[] aValues = daProperty.GetValues(tpAttribute);
foreach (string sVal in aValues)
{
sValue += String.Format("|{0}", sVal);
}
sValue = sValue.TrimStart('|');
}
return sValue;
ZZZZZ
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private string[] GetSiteServers(string DomainName, string ADSite)
{
try
{
return this.GetSiteServers(DomainName, ADSite, null, null);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
new
StackFrame(0,
true).GetMethod().Name, ex.Message));
}
}
private string[] GetSiteServers(string DomainName, string ADSite, string UserID, string UserPW)
{
string sDomainControllers = null;
try
{
using (Domain oDomain = UserID != null && UserPW != null
?
Domain.GetDomain(new
DirectoryContext(DirectoryContextType.Domain,
DomainName, UserID, UserPW))
:
Domain.GetDomain(new
DirectoryContext(DirectoryContextType.Domain,
DomainName)))
{
DomainControllerCollection colDomControllers = (ADSite != null)
? oDomain.FindAllDomainControllers(ADSite)
: oDomain.FindAllDomainControllers();
if (colDomControllers.Count == 0)
{
colDomControllers = oDomain.FindAllDomainControllers();
}
foreach (DomainController DC in colDomControllers)
{
sDomainControllers += String.Format(";{0}", DC.Name);
}
}
sDomainControllers = sDomainControllers.TrimStart(';');
}
catch (Exception ex)
{
throw
new
true).GetMethod().Name, ex.Message));
}
Exception(string.Format("{0}::{1}",
new
return sDomainControllers.Split(';');
}
private string GetDomainNetBIOS(string sDomainFqdn, NetworkCredential netCred)
{
LdapDirectoryIdentifier oLdapDirectory = null;
LdapConnection oLdapConnection = null;
try
{
string sNetBIOS = null;
oLdapDirectory = new LdapDirectoryIdentifier(sDomainFqdn, 389);
oLdapConnection = (netCred == null)
AAAAAA
StackFrame(0,
oLdapConnection.Timeout = TimeSpan.FromSeconds(45);
oLdapConnection.SessionOptions.TcpKeepAlive = true;
oLdapConnection.SessionOptions.ProtocolVersion = 3;
//prevents ldap connection from connecting to other servers during session
oLdapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
oLdapConnection.AutoBind = false;
oLdapConnection.Bind();
SearchResponse
dirRes
(SearchResponse)oLdapConnection.SendRequest(new
SearchRequest(
null,
"configurationNamingContext=*",
System.DirectoryServices.Protocols.SearchScope.Base,
"configurationNamingContext"
));
string
sConfPartDN
dirRes.Entries[0].Attributes["configurationNamingContext"][0].ToString();
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
}
finally
{
oLdapDirectory = null;
new
StackFrame(0,
oLdapConnection.Dispose();
oLdapConnection = null;
}
private
string
GetSecurityDescriptorSDDL(System.Security.AccessControl.AccessControlSections
secSection, byte[] baSecurityDescriptor)
{
try
{
ActiveDirectorySecurity adSec = new ActiveDirectorySecurity();
adSec.SetSecurityDescriptorBinaryForm(baSecurityDescriptor);
return adSec.GetSecurityDescriptorSddlForm(secSection);
}
catch (Exception ex)
{
throw
new
Exception(string.Format("{0}::{1}",
true).GetMethod().Name, ex.Message));
BBBBBB
new
StackFrame(0,
}
}
private Dictionary<string, string> GetNodesInnertext(string sXmlNodes, string[] aNodeNames, bool
bOrdered)
{
try
{
Dictionary<string,
string>(StringComparer.OrdinalIgnoreCase);
string>
dicResult
new
Dictionary<string,
if (bOrdered)
{
int iStart = -1;
int iEnd = -1;
foreach (string sNode in aNodeNames)
{
if (sXmlNodes.Length > iEnd)
{
iStart = sXmlNodes.IndexOf(String.Format(@"<{0}>",
if (iStart >= 0)
{
iStart += (sNode.Length + 2);
iEnd
Exception(string.Format("{0}::{1}",
CCCCCC
new
StackFrame(0,
null;
null;
DDDDDD
null;
null;
null;
set
{
this.sAttributeValue = value;
}
}
public string DistinguishedName
{
get
{
return this.sAttributeValue;
}
set
{
this.sAttributeValue = value;
}
}
public string KeyAttribute
{
get
{
return this.sKeyAttribute;
}
set
{
this.sKeyAttribute = value;
}
}
public string LdapFilter
{
get
{
return this.sLdapFilter;
}
set
{
this.sLdapFilter = value;
}
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bDisposing)
{
if (!this.bDisposed)
{
if (bDisposing)
{
if(this.lGenResults != null)
{
this.lGenResults = null;
}
if(this.lResults != null)
{
this.lResults = null;
}
if(this.dicIndexedTranslatedResults != null)
{
EEEEEE
}
if(this.dicMshipsResults != null)
{
this.dicMshipsResults = null;
}
if(this.dicExtAccessRights != null)
{
this.dicExtAccessRights = null;
}
if (this.dicAttributeList != null)
{
this.dicAttributeList = null;
}
if (this.netCredentials != null)
{
this.netCredentials = null;
}
this.DisposeAllConnections();
}
this.bDisposed = true;
}
}
#endregion
}
}
FFFFFF
IADCONNECTOR.CONFIG.XML
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="configuration" value="configuration" />
<!-- service modes configuration -->
<add key="interval" value="1" />
<add key="schedule" value="22:00" />
<!--1 when have new empty inventory; 0 when doing full resync; 1 or 0 in normal operation-->
<add key="firstrun" value="0" />
</appSettings>
<connectionStrings>
<add
name="iADConnector"
connectionString="Persist
Security
Info=False;Integrated
Security=SSPI;database=iADConnector;server=IP-0A74C61D\SQLEXPRESS;Connect Timeout=120" />
</connectionStrings>
</configuration>
GGGGGG