Info |
---|
This document is a work in progress. |
Table of Contents | ||
---|---|---|
|
Introduction
...
for Ambari versions between 2.0 |
...
Table of Contents | ||
---|---|---|
|
Introduction
Before Ambari 2.0.0, configuring an Ambari cluster to use Kerberos involved setting up the Kerberos client infrastructure on each host, creating the required identities, generating and distributing the needed keytabs files, and updating the necessary configuration properties. On a small cluster this may not seem to be too large of an effort; however as the size of the cluster increases, so does the amount of work that is involved.
This is where Ambari’s Automated Kerberization facility can help. It performs all of these steps and also helps to maintain the cluster as new services and hosts are added.
The Automated Kerberization can be invoked using Ambari’s REST API as well as the Enable Kerberos Wizard in the Ambari UI.
How it works
Stacks and services that can utilize Kerberos credentials for authentication must have a Kerberos Descriptor declaring required Kerberos identities and how to update configurations. The Ambari infrastructure uses this data, and any updates applied by an administrator, to perform Kerberos related operations such as initially enabling Kerberos, enabling Kerberos for on hosts and added components, regenerating credentials, and disabling Kerberos.
It should be notated that it Ambari is required to be installed on a registered host. Also, the Kerberos service is required to be installed on all hosts of the cluster before any automated tasks can be performed. If using the Ambari UI, this should happen as part of the relevant wizard workflow.
Enabling Kerberos
When enabling Kerberos, all of the services in the cluster are expected to be stopped. The main reason for this is to avoid state issues as the services are stopped and then started when the cluster is transitioning to be Kerberized. The following steps are taken to enable Kerberos on the cluster en masse:
This is where Ambari’s Automated Kerberization facility can help. It performs all of these steps and also helps to maintain the cluster as new services and hosts are added.
The Automated Kerberization can be invoked using Ambari’s REST API as well as the Enable Kerberos Wizard in the Ambari UI.
How it works
Stacks and services that can utilize Kerberos credentials for authentication must have a Kerberos Descriptor declaring required Kerberos identities and how to update configurations. The Ambari infrastructure uses this data, and any updates applied by an administrator, to perform Kerberos related operations such as initially enabling Kerberos, enabling Kerberos for on hosts and added components, regenerating credentials, and disabling Kerberos.
It should be notated that it Ambari is required to be installed on a registered host. Also, the Kerberos service is required to be installed on all hosts of the cluster before any automated tasks can be performed. If using the Ambari UI, this should happen as part of the relevant wizard workflow.
Enabling Kerberos
When enabling Kerberos, all of the services in the cluster are expected to be stopped. The main reason for this is to avoid state issues as the services are stopped and then started when the cluster is transitioning to be Kerberized. The following steps are taken to enable Kerberos on the cluster en masse:
- Create or update accounts in the configured KDC (or Active Directory)
- Generate keytab files and distribute them to the appropriate hosts
- Update relevant configurations
Adding Components
If Automated Kerberization was enabled for the Ambari cluster, whenever new components are added, the will automatically be configured for Kerberos and any necessary principals and keytabs will be generated and distributed. For each new component, the following steps will occur before the component is installed and started:
...
- Create or update accounts in the configured KDC (or Active Directory)
- Generate keytab files and distribute them to the appropriate hosts
- Update relevant configurations
Adding
...
Components
If Automated Kerberization was enabled for the Ambari cluster, whenever new components are added, the will automatically be configured for Kerberos and any necessary principals and keytabs will be generated and distributed. For each new component, the following steps will occur before the component is installed and started:
- Update relevant configurations
- Create or update accounts in the configured KDC (or Active Directory)
- Generate keytab files and distribute them to the appropriate hosts
Adding Hosts
...
When adding a new host, the Kerberos client must be installed on it. This does not happen automatically, however the Add Host Wizard in the Ambari UI will will perform this step if Automated Kerberization was enabled for the Ambari cluster. Once host is added, generally one or more components are installed on it - see Adding Components.
...
Service-level auth-to-local-properties is an optional list of zero or more configuration property specifications (config-type/property_name[|concatenation_scheme]) indicating which properties contain auth-to-local rule sets and how to concatenate the rules to meet the property specifications. These sets are dynamically updated using the details from the identities used when Kerberizing the cluster and concatenated as indicated. The concatenation scheme value is optional.
If specified one of the following schemes must be specified:
- new_lines - rules in the rule set are separated by a new line (\n)
- new_lines_escaped - rules in the rule set are separated by a \ and a new line (\ \n)
- spaces - rules in the rule set are separated by a whitespace character (effectively placing all rules in a single line)
If not specified, the default concatenation scheme is new_lines.
Examples
...
Service site property using the default concatenation scheme
core-site/hadoop.security.auth_to_local
Service site property explicitly using the escaped new lines concatenation scheme
startup.properties/http.authentication.kerberos.name.rules|new_lines_escaped
...
"services": [
{
"name": "SERVICE",
"identities": [
...
],
"auth_to_local_properties" : [
...
],
"configurations": [
...
],
"components": [
...
]
},
…
]
components
A component descriptor may exist in the service-level Kerberos Descriptor file. This block is a list of zero or more component descriptors belonging to the containing service descriptor. Each component descriptor is a block containing a component name, an optional identities block, an optional auth_to_local_properties block, and an optional configurations block.
...
{
// One or more services may be listed in a service-level Kerberos
// Descriptor file
"services": [
{
"name": "SERVICE_1",
// Service-level identities to be created if this service is installed.
// Any relevant keytab files will be distributed to hosts with at least
// one of the components on it. "identities": [
// Service-specific identity declaration, declaring all properties
// needed initiate the creation of the principal and keytab files,
// as well as setting the service-specific configurations. This may
// be referenced by contained components using ../service1_identity. {
"name": "service1_identity",
"principal": {
"value": "service1/_HOST@${realm}",
"type" : "service",
"configuration": "service1-site/service1.principal" },
"keytab": {
"file": "${keytab_dir}/service1.service.keytab",
"owner": {
"name": "${service1-env/service_user}",
"access": "r"
},
"group": {
"name": "${cluster-env/user_group}",
"access": "r"
},
"configuration": "service1-site/service1.keytab.file" }
},
// Service-level identity referencing the stack-level spnego
// identity and overriding the principal and keytab configuration
// specifications. {
"name": "/spnego",
"principal": {
"configuration": "service1-site/service1.web.principal"
},
"keytab": {
"configuration": "service1-site/service1.web.keytab.file"
}
},
// Service-level identity referencing the stack-level smokeuser
// identity. No properties are being overridden and overriding
// the principal and keytab configuration specifications.
{ "name": "/smokeuser"
}
],
// Properties related to this service that require the auth-to-local
// rules to be dynamically generated based on identities create for
// the cluster. "auth_to_local_properties" : [
"service1-site/security.auth_to_local"
],
// Configuration properties to be set when this service is installed,
// no matter which components are installed "configurations": [
{
"service-site": {
"service1.security.authentication": "kerberos",
"service1.security.auth_to_local": ""
}
}
],
// A list of components related to this service
"components": [ {
"name": "COMPONENT_1",
// Component-specific identities to be created when this component
// is installed. Any keytab files specified will be distributed
// only to the hosts where this component is installed.
"identities": [ // An identity "local" to this component
{ "name": "component1_service_identity",
"principal": {
"value": "component1/_HOST@${realm}",
"type" : "service",
"configuration": "service1-site/comp1.principal",
"local_username" : "${service1-env/service_user}"
},
"keytab": {
"file": "${keytab_dir}/s1c1.service.keytab",
"owner": {
"name": "${service1-env/service_user}",
"access": "r"
},
"group": {
"name": "${cluster-env/user_group}",
"access": ""
},
"configuration": "service1-site/comp1.keytab.file"
}
},
// The stack-level spnego identity overridden to set component-specific
// configurations
{ "name": "/spnego",
"principal": {
"configuration": "service1-site/comp1.spnego.principal"
},
"keytab": {
"configuration": "service1-site/comp1.spnego.keytab.file"
}
} ],
// Component-specific configurations to set if this component is installed
"configurations": [ {
"service-site": {
"comp1.security.type": "kerberos"
}
}
]
},
{
"name": "COMPONENT_2",
"identities": [
{
"name": "component2_service_identity",
"principal": {
"value": "component2/_HOST@${realm}",
"type" : "service",
"configuration": "service1-site/comp2.principal",
"local_username" : "${service1-env/service_user}"
},
"keytab": {
"file": "${keytab_dir}/s1c2.service.keytab",
"owner": {
"name": "${service1-env/service_user}",
"access": "r"
},
"group": {
"name": "${cluster-env/user_group}",
"access": ""
},
"configuration": "service1-site/comp2.keytab.file"
}
},
// The service-level service1_identity identity overridden to
// set component-specific configurations
{ "name": "../service1_identity",
"principal": {
"configuration": "service1-site/comp2.service.principal"
},
"keytab": {
"configuration": "service1-site/comp2.service.keytab.file"
}
}
], "configurations" : [
{
"service-site" : {
"comp2.security.type": "kerberos"
}
}
]
}
]
}
]
}
" : {
"comp2.security.type": "kerberos"
}
}
]
}
]
}
]
}
The Kerberos Service
Configurations
kerberos-env
kdc_type
The type of KDC being used. Either mit-kdc or active-directory
Possible Values: mit-kdc, active-directory
manage_identities
Indicates whether the Ambari user and service Kerberos identities (principals and keytab files) should be managed (created, deleted, updated, etc...) by Ambari or managed manually.
Possible Values: true, false
install_packages
Indicates whether Ambari should install the Kerberos client package(s) or not. If not, it is expected that Kerberos utility programs (such as kadmin, kinit, klist, and kdestroy) are compatible with MIT Kerberos 5 version 1.10.3 in command line options and behaviors.
Possible Values: true, false
ldap_url
The URL to the Active Directory LDAP Interface. This value must indicate a secure channel using LDAPS since it is required for creating and updating passwords for Active Directory accounts.
Example: ldaps://ad.example.com:636
container_dn
The distinguished name (DN) of the container used store service principals
Example: OU=hadoop,DC=example,DC=com
encryption_types
The supported (space-delimited) list of session key encryption types that should be returned by the KDC.
Default value: aes des3-cbc-sha1 rc4 des-cbc-md5
realm
The default realm to use when creating service principals
Example: EXAMPLE.COM
kdc_host (<Ambari 2.4.0)
The IP address or FQDN for the KDC host. Optionally a port number may be included.
Example: kdc.example.com
Example: kdc.example.com:88
kdc_hosts (>=Ambari 2.4.0)
A comma-delimited list of IP addresses or FQDNs for the list of relevant KDC hosts. Optionally a port number may be included for each entry.
Example: kdc.example.com, kdc1.example.com
Example: kdc.example.com:88, kdc1.example.com:88
admin_server_host
The IP address or FQDN for the KDC Kerberos administrative host. Optionally a port number may be included.
Example: kadmin.example.com
Example: kadmin.example.com:88
executable_search_paths
A comma-delimited list of search paths to use to find Kerberos utilities like kadmin and kinit.
Default value: /usr/bin, /usr/kerberos/bin, /usr/sbin, /usr/lib/mit/bin, /usr/lib/mit/sbin
password_length
The length required length for generated passwords.
Default value: 20
password_min_lowercase_letters
The minimum number of lowercase letters (a-z) required in generated passwords
Default value: 1
password_min_uppercase_letters
The minimum number of uppercase letters (A-Z) required in generated passwords
Default value: 1
password_min_digits
The minimum number of digits (0-9) required in generated passwords
Default value: 1
password_min_punctuation
The minimum number of punctuation characters (?.!$%^*()-_+=~) required in generated passwords
Default value: 1
password_min_whitespace
The minimum number of whitespace characters required in generated passwords
Default value: 0
service_check_principal_name
The principal name to use when executing the Kerberos service check
Example: ${cluster_name}-${short_date}
case_insensitive_username_rules
Force principal names to resolve to lowercase local usernames in auth-to-local rules
Possible values: true, false
Default value: false
ad_create_attributes_template
A Velocity template to use to generate a JSON-formatted document containing the set of attribute names and values needed to create a new Kerberos identity in the relevant Active Directory.
Variables include: principal_name, principal_primary, principal_instance, realm, realm_lowercase, normalized_principal, principal digest, password, is_service, container_dn
Note: This is used only in the case when the kdc-type is active-directory.
Default value:
{
"objectClass": ["top", "person", "organizationalPerson", "user"],
"cn": "$principal_name",
#if( $is_service )
"servicePrincipalName": "$principal_name",
#end
"userPrincipalName": "$normalized_principal",
"unicodePwd": "$password",
"accountExpires": "0",
"userAccountControl": "66048"
}
kdc_create_attributes
The set of attributes to use when creating a new Kerberos identity in the relevant (MIT) KDC.
Note: This is used only in the case when the kdc-type is mit-kdc.
Example: -requires_preauth max_renew_life=7d
krb5-conf
manage_krb5_conf
Indicates whether your krb5.conf file should be managed by the wizard or should you manage it yourself
Possible values: true, false
Default value: false
domains
A comma-separated list of domain names used to map server host names to the Realm name (e.g. .example.com,example.com). This is optional.
Example: host.example.com, example.com, .example.com
conf_dir
The krb5.conf configuration directory
Default value: /etc
content
Customizable krb5.conf template (Jinja template engine)
Example: [libdefaults]
renew_lifetime = 7d
forwardable = true
default_realm = {{realm}}
ticket_lifetime = 24h
dns_lookup_realm = false
dns_lookup_kdc = false
#default_tgs_enctypes = {{encryption_types}}
#default_tkt_enctypes = {{encryption_types}}
{% if domains %}
[domain_realm]
{% for domain in domains.split(',') %}
{{domain}} = {{realm}}
{% endfor %}
{% endif %}
[logging]
default = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
kdc = FILE:/var/log/krb5kdc.log
[realms]
{{realm}} = {
admin_server = {{admin_server_host|default(kdc_host, True)}}
kdc = {{kdc_host}}
}
{# Append additional realm declarations below #}
Enabling Kerberos
Enabling Kerberos on the cluster may be done using the Enable Kerberos Wizard within the Ambari UI or using the REST API.
The Enable Kerberos Wizard (Ambari UI)
The Enable Kerberos Wizard provides an easy to use wizard interface that walks through the process of enabling Kerberos.
The REST API
It is possible to enable Kerberos using Ambari's REST API using the following API calls:
Notes:
- Change the authentication credentials as needed
- curl ... -u username:password ...
- The examples below use
- username: admin
- password: admin
- Change the Ambari server host name and port as needed
- curl ... http://HOST:PORT/api/v1/...
- The example below use
- HOST: AMBERI_SERVER
- PORT: 8080
- Change the cluster name as needed
- curl ... http://.../CLUSTER/...
- The example below use
- CLUSTER: CLUSTER_NAME
- @./payload indicates the the payload data is stored in some file rather than declared inline
- curl ... -d @./payload ...
- The examples below use ./payload which should be replace with the actual file path
- The contents of the payload file are indicated below the curl statement
Add the KERBEROS Service to cluster
curl -H "X-Requested-By:ambari" -u admin:admin -i -X POST http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/services/KERBEROS
Add the KERBEROS_CLIENT component to the KERBEROS service
curl -H "X-Requested-By:ambari" -u admin:admin -i -X POST http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/services/KERBEROS/components/KERBEROS_CLIENT
Create and set KERBEROS service configurations
curl -H "X-Requested-By:ambari" -u admin:admin -i -X PUT -d @./payload http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME
Payload when using an MIT KDC
[
{
"Clusters": {
"desired_config": {
"type": "krb5-conf",
"tag": "version1",
"properties": {
"domains":"",
"manage_krb5_conf": "true",
"conf_dir":"/etc",
"content" : "[libdefaults]\n renew_lifetime = 7d\n forwardable= true\n default_realm = {{realm|upper()}}\n ticket_lifetime = 24h\n dns_lookup_realm = false\n dns_lookup_kdc = false\n #default_tgs_enctypes = {{encryption_types}}\n #default_tkt_enctypes ={{encryption_types}}\n\n{% if domains %}\n[domain_realm]\n{% for domain in domains.split(',') %}\n {{domain}} = {{realm|upper()}}\n{% endfor %}\n{%endif %}\n\n[logging]\n default = FILE:/var/log/krb5kdc.log\nadmin_server = FILE:/var/log/kadmind.log\n kdc = FILE:/var/log/krb5kdc.log\n\n[realms]\n {{realm}} = {\n admin_server = {{admin_server_host|default(kdc_host, True)}}\n kdc = {{kdc_host}}\n }\n\n{# Append additional realm declarations below #}\n"
}
}
}
},
{
"Clusters": {
"desired_config": {
"type": "kerberos-env",
"tag": "version1",
"properties": {
"kdc_type": "mit-kdc",
"manage_identities": "true",
"install_packages": "true",
"encryption_types": "aes des3-cbc-sha1 rc4 des-cbc-md5",
"realm" : "EXAMPLE.COM",
"kdc_host" : "KDC_SERVER",
"admin_server_host" : "KDC_SERVER",
"executable_search_paths" : "/usr/bin, /usr/kerberos/bin, /usr/sbin, /usr/lib/mit/bin, /usr/lib/mit/sbin",
"password_length": "20",
"password_min_lowercase_letters": "1",
"password_min_uppercase_letters": "1",
"password_min_digits": "1",
"password_min_punctuation": "1",
"password_min_whitespace": "0",
"service_check_principal_name" : "${cluster_name}-${short_date}",
"case_insensitive_username_rules" : "false"
} }
}
}
]
Payload when using an Active Directory
[
{
"Clusters": {
"desired_config": {
"type": "krb5-conf",
"tag": "version1",
"properties": {
"domains":"",
"manage_krb5_conf": "true",
"conf_dir":"/etc",
"content" : "[libdefaults]\n renew_lifetime = 7d\n forwardable= true\n default_realm = {{realm|upper()}}\n ticket_lifetime = 24h\n dns_lookup_realm = false\n dns_lookup_kdc = false\n #default_tgs_enctypes = {{encryption_types}}\n #default_tkt_enctypes ={{encryption_types}}\n\n{% if domains %}\n[domain_realm]\n{% for domain in domains.split(',') %}\n {{domain}} = {{realm|upper()}}\n{% endfor %}\n{%endif %}\n\n[logging]\n default = FILE:/var/log/krb5kdc.log\nadmin_server = FILE:/var/log/kadmind.log\n kdc = FILE:/var/log/krb5kdc.log\n\n[realms]\n {{realm}} = {\n admin_server = {{admin_server_host|default(kdc_host, True)}}\n kdc = {{kdc_host}}\n }\n\n{# Append additional realm declarations below #}\n"
}
}
}
},
{
"Clusters": {
"desired_config": {
"type": "kerberos-env",
"tag": "version1",
"properties": {
"kdc_type": "active-directory",
"manage_identities": "true",
"install_packages": "true",
"encryption_types": "aes des3-cbc-sha1 rc4 des-cbc-md5",
"realm" : "EXAMPLE.COM",
"kdc_host" : "AD_HOST",
"admin_server_host" : "AD_HOST",
"ldap_url" : "LDAPS://AD_HOST:PORT",
"container_dn" : "OU=....,....",
"executable_search_paths" : "/usr/bin, /usr/kerberos/bin, /usr/sbin, /usr/lib/mit/bin, /usr/lib/mit/sbin",
"password_length": "20", "password_min_lowercase_letters": "1",
"password_min_uppercase_letters": "1",
"password_min_digits": "1",
"password_min_punctuation": "1",
"password_min_whitespace": "0",
"service_check_principal_name" : "${cluster_name}-${short_date}",
"case_insensitive_username_rules" : "false",
"create_attributes_template" : "{\n \"objectClass\": [\"top\", \"person\", \"organizationalPerson\", \"user\"],\n \"cn\": \"$principal_name\",\n #if( $is_service )\n \"servicePrincipalName\": \"$principal_name\",\n #end\n \"userPrincipalName\": \"$normalized_principal\",\n \"unicodePwd\": \"$password\",\n \"accountExpires\": \"0\",\n \"userAccountControl\": \"66048\"}"
} }
}
}
]
Create the KERBEROS_CLIENT host components (once for each host, replace HOST_NAME)
curl -H "X-Requested-By:ambari" -u admin:admin -i -X POST -d '{"host_components" : [{"HostRoles" : {"component_name":"KERBEROS_CLIENT"}}]}' http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/hosts?Hosts/host_name=HOST_NAME
Install the KERBEROS service and components
curl -H "X-Requested-By:ambari" -u admin:admin -i -X PUT -d '{"ServiceInfo": {"state" : "INSTALLED"}}' http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/services/KERBEROS
Stop all services
curl -H "X-Requested-By:ambari" -u admin:admin -i -X PUT -d '{"RequestInfo":{"context":"Stop Service"},"Body":{"ServiceInfo":{"state":"INSTALLED"}}}' http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/services
Get the default Kerberos Descriptor
curl -H "X-Requested-By:ambari" -u admin:admin -i -X GET http://AMBARI_SERVER:8080/api/v1/stacks/STACK_NAME/versions/STACK_VERSION/artifacts/kerberos_descriptor
Get the customized Kerberos Descriptor (if previously set)
curl -H "X-Requested-By:ambari" -u admin:admin -i -X GET http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/artifacts/kerberos_descriptor
Set the Kerberos Descriptor
curl -H "X-Requested-By:ambari" -u admin:admin -i -X POST -d @./payload http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/artifacts/kerberos_descriptor
Payload
The Kerberos Descriptor payload may be a complete Kerberos Descriptor or just the updates to overlay on top of the default Kerberos Descriptor.
Enable Kerberos
curl -H "X-Requested-By:ambari" -u admin:admin -i -X PUT -d @./payload http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME
Payload
{
"session_attributes" : { "kerberos_admin" : {
"principal" : "ADMIN_PRINCIPAL",
"password" : "ADMIN_PASSWORD"
}
},
"Clusters": {
"security_type" : "KERBEROS"
}
}
Start all services
curl -H "X-Requested-By:ambari" -u admin:admin -i -X PUT -d '{"ServiceInfo": {"state" : "STARTED"}}' http://AMBARI_SERVER:8080/api/v1/clusters/CLUSTER_NAME/services
Technical Information
Password Generation
When Ambari generates keytab files, it uses an internal mechanism rather than rely on the KDC or Active Directory to do it. This is mainly because Ambari cannot request a keytab file from an Active Directory. Because of this, Ambari needs to know the password for each Kerberos identity that needs a keytab file created and thus it sets or updates the identity's password a needed.
The password for each Ambari-managed account in a KDC or Active Directory is randomly generated and stored only long enough to set the account's password and generate the keytab file.
Ambari 2.0.x
Generated passwords in Ambari 2.0.x meet the following specifications
- Randomly generated using 18 characters from the following set:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890?.!$%^*()-_+=~
- Each character is chosen via index in the set using a static instance of the
java.security.SecureRandom
class (see http://docs.oracle.com/javase/7/docs/api/java/security/SecureRandom.html)
Ambari 2.1.x (and above)
Passwords in Ambari 2.1.x (and above) are generated using the following user-settable parameters:
- Password length (kerberos-env/password_length), default 20
- Minimum number of lower-cased letters (kerberos-env/password_min_lowercase_letters), default 1
- Set:
abcdefghijklmnopqrstuvwxyz
- Set:
- Minimum number of upper-cased letters (kerberos-env/password_min_uppercase_letters), default 1
- Set:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
- Set:
- Minimum number of digits (kerberos-env/password_min_digits), default 1
- Set:
1234567890
- Set:
- Minimum number of punctuation characters (kerberos-env/password_min_punctuation), default 1
- Set:
?.!$%^*()-_+=~
- Set:
- Minimum number of whitespace characters (kerberos-env/password_min_whitespace), default 0
- Set: (space character)
The following algorithm is executed:
- Create an array to store password characters
- For each character class (upper-case letter, lower-case letter, digit, ...), randomly select from the relevant set the minimum number of characters and store them in the array
- For the number of characters calculated as the difference between the expected password length and the number of characters already collected, randomly select a character from a randomly-selected character class and store into the array
- For the number of characters expected in the password, randomly pull one from the array and append to the password result
- Return the generated password
To generate a random integer used to identify an index within a character set, static instance of the java.security.SecureRandom
class (see http://docs.oracle.com/javase/7/docs/api/java/security/SecureRandom.html) is used.
(more to come...(more to come)