OPENDJ-3036 Fix inconsistent field naming in Rest2Ldap config files
* aligned key manager configuration field names with trust manager
* use camel-case throughout configuration (e.g. URL -> Url, DN -> Dn)
* simplify parsing of WritabilityPolicy.
| | |
| | | // the request against the access-token resolver endpoint. Acceptable values are: |
| | | // |
| | | // "jvm" - use the JVM's default keystore for retrieving certificates. (default) |
| | | // "keystore" - use the named key store file for retrieving certificates. |
| | | // "file" - use a file-based key store for retrieving certificates. |
| | | // "pkcs11" - use a PKCS#11 token for retrieving certificates. |
| | | "keyManager": "jvm", |
| | | |
| | | // Keystore based key manager configuration (see above). |
| | | "keyStoreFile": "/path/to/keystore", |
| | | "keyStorePasswordFile": "/path/to/pinfile", |
| | | "keyStoreFormat": "JKS", |
| | | "keyStoreProvider": "", |
| | | "fileBasedKeyManagerType": "JKS", |
| | | "fileBasedKeyManagerFile": "/path/to/keystore", |
| | | "fileBasedKeyManagerPasswordFile": "/path/to/pinfile", |
| | | |
| | | // PKCS11 based key manager configuration |
| | | "pkcs11PasswordFile": "/path/to/pinfile" |
| | | "pkcs11KeyManagerPasswordFile": "/path/to/pinfile" |
| | | }, |
| | | |
| | | // The array of connection factories which will be used by the Rest2LDAP |
| | |
| | | "heartBeatTimeoutMilliSeconds": 500, |
| | | |
| | | // The preferred load-balancing pool. |
| | | "primaryLDAPServers": [{ |
| | | "primaryLdapServers": [{ |
| | | "hostname": "localhost", |
| | | "port": 1389 |
| | | }], |
| | | // The fail-over load-balancing pool (optional). |
| | | "secondaryLDAPServers": [ |
| | | "secondaryLdapServers": [ |
| | | // Empty. |
| | | ] |
| | | }, |
| | |
| | | // to allow the user configured here to perform proxied authorization. |
| | | "authentication": { |
| | | "simple": { |
| | | "bindDN": "cn=directory manager", |
| | | "bindDn": "cn=directory manager", |
| | | "bindPassword": "password" |
| | | } |
| | | } |
| | |
| | | // The Bind DN Template containing a single {username} which will be replaced by the authenticating |
| | | // user's name. (i.e: uid={username},ou=People,dc=example,dc=com) |
| | | // If missing, "{username}" is used. |
| | | "bindDNTemplate": "uid={username},ou=People,dc=example,dc=com" |
| | | "bindDnTemplate": "uid={username},ou=People,dc=example,dc=com" |
| | | }, |
| | | |
| | | // Bind to the LDAP server using a SASL Plain request |
| | |
| | | "search": { |
| | | // Connection factory used to perform the search operation. |
| | | // If missing, "root" factory will be used. |
| | | "searchLDAPConnectionFactory": "root", |
| | | "searchLdapConnectionFactory": "root", |
| | | |
| | | // Connection factory used to perform the bind operation. |
| | | // If missing, "bind" factory will be used. |
| | | "bindLDAPConnectionFactory": "bind", |
| | | "bindLdapConnectionFactory": "bind", |
| | | |
| | | // The {username} filter format parameters will be substituted with the client-provided username, |
| | | // using LDAP filter string character escaping. |
| | | "baseDN": "ou=people,dc=example,dc=com", |
| | | "baseDn": "ou=people,dc=example,dc=com", |
| | | "scope": "sub", // Or "one". |
| | | "filterTemplate": "(&(uid={username})(objectClass=inetOrgPerson))" |
| | | } |
| | |
| | | "openam": { |
| | | // Defines the OpenAM endpoint URL where the request should be sent. |
| | | // This attribute is required and must have a string syntax. |
| | | "endpointURL": "http://openam.example.com:8080/openam/oauth2/tokeninfo", |
| | | "endpointUrl": "http://openam.example.com:8080/openam/oauth2/tokeninfo", |
| | | |
| | | // This alias points at an existing certificate that is used for SSL authentication for secure |
| | | // communication between this gateway and the OpenAM access-token resolver. |
| | |
| | | "rfc7662": { |
| | | // Defines the token introspection endpoint URL where the request should be sent. |
| | | // This attribute is required and must have a string syntax. |
| | | "endpointURL": "http://openam.example.com:8080/openam/oauth2/myrealm/introspect", |
| | | "endpointUrl": "http://openam.example.com:8080/openam/oauth2/myrealm/introspect", |
| | | |
| | | // This alias points at an existing certificate that is used for SSL authentication for secure |
| | | // communication between this gateway and the introspection access-token resolver. |
| | |
| | | |
| | | // The access token base DN. |
| | | // This attribute is required and must have a string syntax. |
| | | "baseDN": "ou=famrecords,ou=openam-session,ou=tokens,dc=example,dc=com", |
| | | "baseDn": "ou=famrecords,ou=openam-session,ou=tokens,dc=example,dc=com", |
| | | |
| | | // The default authzIdTemplate demonstrates how an authorization DN may be constructed |
| | | // from the "userName" field in the following example CTS access token entry: |
| | |
| | | final JsonValue openAm = configuration.get("openam"); |
| | | return new OpenAmAccessTokenResolver(newHttpClientHandler(openAm), |
| | | TimeService.SYSTEM, |
| | | openAm.get("endpointURL").required().asString()); |
| | | openAm.get("endpointUrl").required().asString()); |
| | | case CTS: |
| | | final JsonValue cts = configuration.get("cts").required(); |
| | | return newCtsAccessTokenResolver( |
| | | getConnectionFactory(cts.get("ldapConnectionFactory").defaultTo(DEFAULT_ROOT_FACTORY).asString()), |
| | | cts.get("baseDN").required().asString()); |
| | | cts.get("baseDn").required().asString()); |
| | | case FILE: |
| | | return newFileAccessTokenResolver(configuration.get("file").get("folderPath").required().asString()); |
| | | default: |
| | |
| | | |
| | | private AccessTokenResolver parseRfc7662Resolver(final JsonValue configuration) throws HttpApplicationException { |
| | | final JsonValue rfc7662 = configuration.get("rfc7662").required(); |
| | | final String introspectionEndPointURL = rfc7662.get("endpointURL").required().asString(); |
| | | final String introspectionEndPointURL = rfc7662.get("endpointUrl").required().asString(); |
| | | try { |
| | | return newRfc7662AccessTokenResolver(newHttpClientHandler(rfc7662), |
| | | new URI(introspectionEndPointURL), |
| | |
| | | private AuthenticationStrategy buildSimpleBindStrategy(final JsonValue config) { |
| | | return newSimpleBindStrategy(getConnectionFactory(config.get("ldapConnectionFactory") |
| | | .defaultTo(DEFAULT_BIND_FACTORY).asString()), |
| | | parseUserNameTemplate(config.get("bindDNTemplate").defaultTo("%s")), |
| | | parseUserNameTemplate(config.get("bindDnTemplate").defaultTo("%s")), |
| | | schema); |
| | | } |
| | | |
| | |
| | | private AuthenticationStrategy buildSearchThenBindStrategy(JsonValue config) { |
| | | return newSearchThenBindStrategy( |
| | | getConnectionFactory( |
| | | config.get("searchLDAPConnectionFactory").defaultTo(DEFAULT_ROOT_FACTORY).asString()), |
| | | config.get("searchLdapConnectionFactory").defaultTo(DEFAULT_ROOT_FACTORY).asString()), |
| | | getConnectionFactory( |
| | | config.get("bindLDAPConnectionFactory").defaultTo(DEFAULT_BIND_FACTORY).asString()), |
| | | DN.valueOf(config.get("baseDN").required().asString(), schema), |
| | | config.get("bindLdapConnectionFactory").defaultTo(DEFAULT_BIND_FACTORY).asString()), |
| | | DN.valueOf(config.get("baseDn").required().asString(), schema), |
| | | SearchScope.valueOf(config.get("scope").required().asString().toLowerCase()), |
| | | parseUserNameTemplate(config.get("filterTemplate").required())); |
| | | } |
| | |
| | | } |
| | | |
| | | private static WritabilityPolicy parseWritability(final JsonValue mapper) { |
| | | if (mapper.isDefined("writability")) { |
| | | final String writability = mapper.get("writability").asString(); |
| | | if (writability.equalsIgnoreCase("readOnly")) { |
| | | return WritabilityPolicy.READ_ONLY; |
| | | } else if (writability.equalsIgnoreCase("readOnlyDiscardWrites")) { |
| | | return WritabilityPolicy.READ_ONLY_DISCARD_WRITES; |
| | | } else if (writability.equalsIgnoreCase("createOnly")) { |
| | | return WritabilityPolicy.CREATE_ONLY; |
| | | } else if (writability.equalsIgnoreCase("createOnlyDiscardWrites")) { |
| | | return WritabilityPolicy.CREATE_ONLY_DISCARD_WRITES; |
| | | } else if (writability.equalsIgnoreCase("readWrite")) { |
| | | return WritabilityPolicy.READ_WRITE; |
| | | } else { |
| | | throw newJsonValueException(mapper, ERR_CONFIG_UNKNOWN_WRITABILITY.get(writability, |
| | | "readOnly, readOnlyDiscardWrites, createOnly, createOnlyDiscardWrites, readWrite")); |
| | | } |
| | | } else { |
| | | return WritabilityPolicy.READ_WRITE; |
| | | } |
| | | return mapper.get("writability").defaultTo("readWrite").as(enumConstant(WritabilityPolicy.class)); |
| | | } |
| | | |
| | | /** Indicates whether LDAP client connections should use SSL or StartTLS. */ |
| | |
| | | private enum TrustManagerType { TRUSTALL, JVM, FILE } |
| | | |
| | | /** Specifies the type of key-store to use when performing SSL client authentication. */ |
| | | private enum KeyManagerType { JVM, KEYSTORE, PKCS11 } |
| | | private enum KeyManagerType { JVM, FILE, PKCS11 } |
| | | |
| | | /** |
| | | * Configures a {@link X509KeyManager} using the provided JSON configuration. |
| | |
| | | switch (keyManagerType) { |
| | | case JVM: |
| | | return useJvmDefaultKeyStore(); |
| | | case KEYSTORE: |
| | | final String fileName = config.get("keyStoreFile").required().asString(); |
| | | final String passwordFile = config.get("keyStorePasswordFile").asString(); |
| | | case FILE: |
| | | final String fileName = config.get("fileBasedKeyManagerFile").required().asString(); |
| | | final String passwordFile = config.get("fileBasedKeyManagerPasswordFile").asString(); |
| | | final String password = passwordFile != null |
| | | ? readPasswordFromFile(passwordFile) |
| | | : config.get("keyStorePassword").asString(); |
| | | final String format = config.get("keyStoreFormat").asString(); |
| | | final String provider = config.get("keyStoreProvider").asString(); |
| | | return useKeyStoreFile(fileName, password != null ? password.toCharArray() : null, format, provider); |
| | | ? readPasswordFromFile(passwordFile) : config.get("fileBasedKeyManagerPassword").asString(); |
| | | final String type = config.get("fileBasedKeyManagerType").asString(); |
| | | final String provider = config.get("fileBasedKeyManagerProvider").asString(); |
| | | return useKeyStoreFile(fileName, password != null ? password.toCharArray() : null, type, provider); |
| | | case PKCS11: |
| | | final String pkcs11PasswordFile = config.get("pkcs11PasswordFile").asString(); |
| | | final String pkcs11PasswordFile = config.get("pkcs11KeyManagerPasswordFile").asString(); |
| | | return usePKCS11Token(pkcs11PasswordFile != null |
| | | ? readPasswordFromFile(pkcs11PasswordFile).toCharArray() |
| | | : null); |
| | | ? readPasswordFromFile(pkcs11PasswordFile).toCharArray() : null); |
| | | default: |
| | | throw new IllegalArgumentException("Unsupported key-manager type: " + keyManagerType); |
| | | } |
| | |
| | | if (authn.isDefined("simple")) { |
| | | final JsonValue simple = authn.get("simple"); |
| | | final BindRequest bindRequest = |
| | | Requests.newSimpleBindRequest(simple.get("bindDN").required().asString(), |
| | | Requests.newSimpleBindRequest(simple.get("bindDn").required().asString(), |
| | | simple.get("bindPassword").required().asString().toCharArray()); |
| | | options.set(AUTHN_BIND_REQUEST, bindRequest); |
| | | } else { |
| | |
| | | } |
| | | |
| | | // Parse primary data center. |
| | | final JsonValue primaryLdapServers = configuration.get("primaryLDAPServers"); |
| | | final JsonValue primaryLdapServers = configuration.get("primaryLdapServers"); |
| | | if (!primaryLdapServers.isList() || primaryLdapServers.size() == 0) { |
| | | throw new IllegalArgumentException("No primaryLDAPServers"); |
| | | throw new IllegalArgumentException("No primaryLdapServers"); |
| | | } |
| | | final ConnectionFactory primary = parseLdapServers(primaryLdapServers, connectionPoolSize, options); |
| | | |
| | | // Parse secondary data center(s). |
| | | final JsonValue secondaryLdapServers = configuration.get("secondaryLDAPServers"); |
| | | final JsonValue secondaryLdapServers = configuration.get("secondaryLdapServers"); |
| | | ConnectionFactory secondary = null; |
| | | if (secondaryLdapServers.isList()) { |
| | | if (secondaryLdapServers.size() > 0) { |
| | |
| | | * modified afterwards. Attempts to update the attribute will result in an |
| | | * error. |
| | | */ |
| | | READ_ONLY(false), |
| | | READ_ONLY("readOnly", false), |
| | | |
| | | /** |
| | | * The attribute cannot be provided when creating a new resource, nor |
| | | * modified afterwards. Attempts to update the attribute will not result in |
| | | * an error (the new values will be ignored). |
| | | */ |
| | | READ_ONLY_DISCARD_WRITES(true), |
| | | READ_ONLY_DISCARD_WRITES("readOnlyDiscardWrites", true), |
| | | |
| | | /** |
| | | * The attribute may be provided when creating a new resource, but cannot be |
| | | * modified afterwards. Attempts to update the attribute will result in an |
| | | * error. |
| | | */ |
| | | CREATE_ONLY(false), |
| | | CREATE_ONLY("createOnly", false), |
| | | |
| | | /** |
| | | * The attribute may be provided when creating a new resource, but cannot be |
| | | * modified afterwards. Attempts to update the attribute will not result in |
| | | * an error (the new values will be ignored). |
| | | */ |
| | | CREATE_ONLY_DISCARD_WRITES(true), |
| | | CREATE_ONLY_DISCARD_WRITES("createOnlyDiscardWrites", true), |
| | | |
| | | /** |
| | | * The attribute may be provided when creating a new resource, and modified |
| | | * afterwards. |
| | | */ |
| | | READ_WRITE(false); |
| | | READ_WRITE("readWrite", false); |
| | | // @formatter:on |
| | | |
| | | private final String name; |
| | | private final boolean discardWrites; |
| | | |
| | | private WritabilityPolicy(final boolean discardWrites) { |
| | | WritabilityPolicy(final String name, final boolean discardWrites) { |
| | | this.name = name; |
| | | this.discardWrites = discardWrites; |
| | | } |
| | | |
| | |
| | | boolean discardWrites() { |
| | | return discardWrites; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return name; |
| | | } |
| | | } |
| | |
| | | + "'requiredScopes': ['read', 'write', 'dolphin']," |
| | | + "'resolver': 'openam'," |
| | | + "'openam': {" |
| | | + " 'endpointURL': 'http://www.example.com/token-info'," |
| | | + " 'endpointUrl': 'http://www.example.com/token-info'," |
| | | + " 'authzIdTemplate': 'userName: ou={/user/id},dc=example,dc=com'" |
| | | + "}," |
| | | + "'accessTokenCache': {'enabled': true, 'cacheExpiration': '42'}}", |
| | |
| | | + "'requiredScopes': ['read', 'write', 'dolphin']," |
| | | + "'resolver': 'openam'," |
| | | + "'openam': {" |
| | | + " 'endpointURL': 'http://www.example.com/token-info'," |
| | | + " 'endpointUrl': 'http://www.example.com/token-info'," |
| | | + " 'authzIdTemplate': 'dn: ou={/user/id},dc=example,dc=com'" |
| | | + "}," |
| | | + "'accessTokenCache': {'enabled': true, 'cacheExpiration': '42'}}", |
| | |
| | | + "'requiredScopes': []," |
| | | + "'resolver': 'openam'," |
| | | + "'openam': {" |
| | | + " 'endpointURL': 'http://www.example.com/token-info'," |
| | | + " 'endpointUrl': 'http://www.example.com/token-info'," |
| | | + " 'authzIdTemplate': 'dn: ou={/user/id},dc=example,dc=com'" |
| | | + "}}"; |
| | | fakeApp.buildOAuth2Filter(parseJson(config)); |
| | |
| | | return new Object[][] { |
| | | { |
| | | "{'resolver': 'rfc7662'," |
| | | + "'rfc7662': { 'endpointURL': 'http:/example.com/introspect'," |
| | | + "'rfc7662': { 'endpointUrl': 'http:/example.com/introspect'," |
| | | + " 'clientId': 'client_app_id'," |
| | | + " 'clientSecret': 'client_app_secret'," |
| | | + " 'authzIdTemplate': 'dn: ou={/user/id},dc=example,dc=com'}}" |
| | |
| | | { |
| | | "{'resolver': 'openam'," |
| | | + "'openam': { " |
| | | + " 'endpointURL': 'http:/example.com/tokeninfo'," |
| | | + " 'endpointUrl': 'http:/example.com/tokeninfo'," |
| | | + " 'authzIdTemplate': 'dn: ou={/user/id},dc=example,dc=com'}}" |
| | | }, |
| | | { |
| | | "{'resolver': 'cts'," |
| | | + "'cts': { 'baseDN': 'coreTokenId={token},dc=com'," |
| | | + "'cts': { 'baseDn': 'coreTokenId={token},dc=com'," |
| | | + " 'authzIdTemplate': 'dn: ou={/user/id},dc=example,dc=com'}}" |
| | | }, |
| | | { |