[prev in list] [next in list] [prev in thread] [next in thread] 

List:       forgerock-openidm
Subject:    [OpenIDM] using LDAP instead of MySQL
From:       Bang.Hong () compuware ! com (Hong, Bang (Vincent))
Date:       2012-11-30 2:19:46
Message-ID: BB59A4D5487F4C4A94E0FB5CA19961E108AF5AA1 () SN2PRD0510MB382 ! namprd05 ! prod ! outlook ! com
[Download RAW message or body]

Hi,

Thank you for you update.

I really have not think about the same configuration on different node. Thank you.


From: openidm-bounces@forgerock.org [mailto:openidm-bounces at forgerock.org] On \
                Behalf Of L?szl? Hord?s
Sent: 2012?11?29? 19:25
To: openidm at forgerock.org
Cc: La Joie, Chad
Subject: Re: [OpenIDM] using LDAP instead of MySQL

Hi,

If I understood you correctly you don't want to use MySQL (JDBC Repo Service) at all. \
If it is your intention then you need to fill the hole of /repo service and you need \
to define that router prefix for your custom service. The change will be transparent \
from OpenIDM as long as you can store in LDAP the config, link, audit and user object \
in your LDAP.

See the other answers inline below.

Regards,
Laszlo

On 29 Nov 2012, at 10:50, Hong, Bang (Vincent) wrote:


Thank your update.

I am planning to store configuration in ldap server because of cluster. We  want to \
use ldap replication to replicate configuration files. If we are using file and \
memory, we have to make a program to sync those configuration file?

It depends on what is the authoritative source of your configuration. You use OpenIDM \
2.0.3 in a clustered environment and you share the configurations that means all \
server has the same configuration and if you schedule a job all server will pick it \
up and execute it. This issue is addressed in the latest 2.1 version which will be \
released soon.

If you keep the configs in files and you configure all node independently and store \
the configuration in the memory then you don't need to sync anything. You have many \
choices to install the OSGi config objects.


And still there are following things I have not think very clearly
1.       In your case, we need develop a LDAPRepoService, and make the ROUTER_PREFIX \
also as repo. If that meaning we need remove openidm-repo-jdbc-2.0.3.jar from \
openidm/bundle/init folder ? because this jar also define  ROUTER_PREFIX as repo

Yes, you have to replace it with your custom module.


2.       If we have to store configuration in LDAP, if there are one solution to do \
it ?

No, we don't have anything like that.



Thank you


From: openidm-bounces@forgerock.org<mailto:openidm-bounces at forgerock.org> \
                [mailto:openidm-bounces at forgerock.org] On Behalf Of L?szl? Hord?s
Sent: 2012?11?29? 17:16
To: openidm at forgerock.org<mailto:openidm at forgerock.org>
Subject: Re: [OpenIDM] using LDAP instead of MySQL

Hi,

We also planning to use OpenDJ as repository for OpenIDM in the close future but \
focusing your questions it should be possible. There are just few questions.

Do you want to store the configuration in LDAP or are you happy to have them in files \
and loaded them to the memory? If Yes then you can implement a simple in memory \
version and get ride of our JDBC and Orient Repo service.


public class Activator implements BundleActivator {

    ServiceRegistration<RepoBootService> serviceRegistration = null;

    public void start(BundleContext context) throws Exception {
        // Register bootstrap repo
        Hashtable<String, String> prop = new Hashtable<String, String>();
        prop.put(Constants.SERVICE_PID, "org.forgerock.openidm.bootrepo");
        prop.put(ServerConstants.ROUTER_PREFIX, "bootrepo");
        prop.put("db.type", "MEM");
        serviceRegistration =
                context.registerService(RepoBootService.class, new BootService(), \
prop);  }

    public void stop(BundleContext context) throws Exception {
        if (null != serviceRegistration) {
            serviceRegistration.unregister();
        }
    }
}

and the BootService is a simple one like:

public class BootService implements RepoBootService {

    Logger logger = LoggerFactory.getLogger(BootService.class);

    public enum Method {
        create, read, update, delete, patch, query, action
    }

    ConcurrentMap<String, JsonValue> configCacheMap = new ConcurrentHashMap<String, \
JsonValue>();

    public JsonValue handle(JsonValue request) throws JsonResourceException {
        try {
            String id = request.get("id").required().asString();
            String rev = request.get("rev").asString();
            JsonValue value = request.get("value");
            JsonValue params = request.get("params");
            JsonValue response = null;
            try {
                switch (request.get("method").required().asEnum(Method.class)) {
                case create:
                    logger.debug("Call {} method: ID: {}", new Object[] { \
Method.create, id });  if (configCacheMap.containsKey(id)) {
                        throw new \
JsonResourceException(JsonResourceException.BAD_REQUEST,  "Config already exists" + \
id);  }
                    configCacheMap.put(id, value);
                    response = new JsonValue(new HashMap<String, Object>());
                    response.put(ServerConstants.OBJECT_PROPERTY_ID, id);
                    return response;
                case read:
                    logger.debug("Call {} method: ID: {}", new Object[] { \
Method.read, id });  response = configCacheMap.get(id);
                    if (null == response) {
                        throw new \
JsonResourceException(JsonResourceException.NOT_FOUND, id);  }
                    return response;
                case update:
                    logger.debug("Call {} method: ID: {}", new Object[] { \
Method.update, id });  response = configCacheMap.get(id);
                    if (null == response) {
                        throw new \
JsonResourceException(JsonResourceException.NOT_FOUND, id);  }
                    configCacheMap.put(id, value);
                    response = new JsonValue(new HashMap<String, Object>());
                    response.put(ServerConstants.OBJECT_PROPERTY_ID, id);
                    return response;
                case delete:
                    logger.debug("Call {} method: ID: {}", new Object[] { \
Method.delete, id });  response = configCacheMap.get(id);
                    if (null == response) {
                        throw new \
JsonResourceException(JsonResourceException.NOT_FOUND, id);  }
                    configCacheMap.remove(id);
                    response = new JsonValue(new HashMap<String, Object>());
                    return response;
                case patch:
                    throw new JsonResourceException(JsonResourceException.FORBIDDEN);
                case query:
                    JsonValue queryId = params.get(QueryConstants.QUERY_ID);
                    logger.debug("Call {} method: ID: {}, QueryID:", new Object[] { \
Method.query,  id, queryId });
                    if (!queryId.isNull()) {
                        if (QueryConstants.QUERY_ALL_IDS.equals(queryId.asString())) \
                {
                            response = new JsonValue(new HashMap<String, Object>());
                            List<Map<String, Object>> result =
                                    new ArrayList<Map<String, \
                Object>>(configCacheMap.size());
                            for (Map.Entry<String, JsonValue> conf : \
                configCacheMap.entrySet()) {
                                Map<String, Object> item = new HashMap<String, \
                Object>(2);
                                item.put(ServerConstants.OBJECT_PROPERTY_ID, \
conf.getKey());  result.add(item);
                            }
                            response.put(QueryConstants.QUERY_RESULT, result);
                        } else {
                            // Unknown query id
                            throw new \
JsonResourceException(JsonResourceException.BAD_REQUEST,  "Unknown query id: " + \
queryId);  }
                    } else {
                        throw new \
                JsonResourceException(JsonResourceException.BAD_REQUEST,
                                "Query request does not contain valid query");
                    }
                    return response;
                case action:
                    throw new JsonResourceException(JsonResourceException.FORBIDDEN);
                default:
                    throw new \
JsonResourceException(JsonResourceException.BAD_REQUEST);  }
            } catch (JsonValueException jve) {
                throw new JsonResourceException(JsonResourceException.BAD_REQUEST, \
jve);  }
        } catch (Exception e) {
            if (e instanceof JsonResourceException) { // no rethrowing necessary
                throw (JsonResourceException) e;
            } else { // need to rethrow as resource exception
                throw new JsonResourceException(JsonResourceException.INTERNAL_ERROR, \
e);  }

        }
    }
}

If you configure the launcher.json to start your BootService then OpenIDM starts \
without any issue.

            {
                "location":"bundle",
                "includes":[
                    "**/openidm-system-*.jar"
                ],
                "start-level":1,
                "action":"install.start"
            },
            {
                "location":"bundle",
                "includes":[
                    "**/openidm-security-jetty*.jar",
                    "**/openidm-jetty-fragment*.jar",
                    "**/openidm-quartz-fragment*.jar",
                    "**/openidm-config*.jar",
                    "**/openidm-crypto*.jar"
                ],
                "start-level":2,
                "action":"install.start"
            },
            {
                "location":"bundle",
                "includes":[
                    "**/YOUR_CUSTOM_BUNDLE*.jar",
                    "**/org.apache.felix.scr-*.jar"
                ],
                "start-level":3,
                "action":"install.start"
            }


Implementing LDAP repo my suggestion would be to implement a class like this:

@Component(name = "org.forgerock.openidm.ldap.repo", policy = \
ConfigurationPolicy.REQUIRE,  description = "OpenIDM LDAP repository")
@Service(value = { RepositoryService.class, JsonResource.class })
@Properties({
    @Property(name = Constants.SERVICE_VENDOR, value = \
ServerConstants.SERVER_VENDOR_NAME),  @Property(name = Constants.SERVICE_DESCRIPTION, \
value = "OpenIDM LDAP Repository"),  @Property(name = ServerConstants.ROUTER_PREFIX, \
value = "repo"),  @Property(name = "db.type", value = "ldap") })
public class LDAPRepositoryService extends SimpleJsonResource implements \
RepositoryService {

}

There is a simple unit test and you can get the request

import static org.mockito.Mockito.mock;

public class LDAPRepositoryServiceTest {

    private LDAPRepositoryService testabel = null;
    private ComponentContext context = mock(ComponentContext.class);
    private UniversalConnectionPoolManager mgr = null;

    @BeforeTest
    public void createService() throws Exception {
        InputStream inputStream = \
LDAPRepositoryServiceTest.class.getResourceAsStream("/ldap.repo.json");  \
assertNotNull(inputStream);  ByteArrayOutputStream buffer = new \
ByteArrayOutputStream();  byte[] temp = new byte[1024];
        int read;
        while ((read = inputStream.read(temp)) > 0) {
            buffer.write(temp, 0, read);
        }
        String config = new String(buffer.toByteArray());

        Dictionary properties = new Hashtable<String, Object>();
        properties.put(JSONConfigInstaller.JSON_CONFIG_PROPERTY, config);

        //stubbing
        when(context.getProperties()).thenReturn(properties);

        testabel = new LDAPRepositoryService();
        testabel.activate(context);
    }

    @AfterTest
    public void stopService() throws Exception {
        testabel.deactivate(context);
    }

    protected JsonValue loadRequest(String testFile) throws Exception {
        InputStream inputStream = \
LDAPRepositoryServiceTest.class.getResourceAsStream(testFile);  \
assertNotNull(inputStream);  JsonValue request = null;
        try {
            Map jsonObject = (new ObjectMapper()).readValue(inputStream, Map.class);
            request = new JsonValue(jsonObject);
        } finally {
            inputStream.close();
        }
        assertNotNull(request);
        return request;
    }

    @Test
    public void createUser() throws Exception {
        JsonValue request = loadRequest("/request-create-user.json");
        JsonValue response = testabel.handle(request);
        assertThat(response.required().asMap())
                .includes(MapAssert.entry(ServerConstants.OBJECT_PROPERTY_ID, \
"76680e8a-2d5a-4394-885a-6269f1cbccba"));  }

You can save the requests into a JSON file when you debugging OpenIDM and replay them \
in the unit test.

I hope this helps to implement your custom LDAP repository.

The Repo audit logger will call your service to save the Log object so I don't think \
you need a custom one but you should be able to implement and configure our service \
to use yours. This was our intend, make it extendable.

Please don't replace the ManagedObjectSet service. It's a fronted before the \
repository service so all /managed/* call is redirected to /repo/managed/*


Regards,
Laszlo

On 29 Nov 2012, at 09:40, Hong, Bang (Vincent) wrote:



Hi all

We are planning to using LDAP instead of Mysql in OpenIDM. My solution is
1.       Develop new LDAP schema with objectclass which is similar with mysql schema.
2.       Develop a bundle which also implement OpenIDM interface to support CURD to \
instead of ManagedObjectService. 3.       Develop another bundle to store user to \
Ldap with standard schema.

But we found something is hard to extension, so far I found following area just like \
hard-coding Audit log: which can config by audit.log, but only CSV and Repository \
                supported, we could not extend it.
RepoPersistenceManager: This is for configuration when OSGI start, but it will \
hard-coding to invoke JDBCRepository, We can develop a manager like this one, but I \
                could not remove RepoPersistenceManager.
ManagedObjectSet: Since there are one feature for password sync, the password sync \
plug-in will notify openidm with /managed/user and patch method. But if we are using \
Ldap, we have to change it accordingly.

Perhaps my understand is not very experience, but if we can find a way to use LDAP by \
extension and do not modify openidm source coding?

Thank you


Best Regards,
Vincent Hong

_______________________________________________
OpenIDM mailing list
OpenIDM at forgerock.org<mailto:OpenIDM at forgerock.org>
https://lists.forgerock.org/mailman/listinfo/openidm

_______________________________________________
OpenIDM mailing list
OpenIDM at forgerock.org<mailto:OpenIDM at forgerock.org>
https://lists.forgerock.org/mailman/listinfo/openidm

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.forgerock.org/pipermail/openidm/attachments/20121130/ffdfb993/attachment-0001.html \



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic