Repository: karaf Updated Branches: refs/heads/karaf-2.3.x 743e8cde8 -> 54e7493cd
[KARAF-3166] Add JAAS SyncopeLoginModule Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/855d1983 Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/855d1983 Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/855d1983 Branch: refs/heads/karaf-2.3.x Commit: 855d1983624e0a6f8e8d1dbd16e9377295e93195 Parents: 743e8cd Author: Jean-Baptiste Onofré <[email protected]> Authored: Mon Aug 18 11:38:18 2014 +0200 Committer: Jean-Baptiste Onofré <[email protected]> Committed: Mon Aug 18 11:40:47 2014 +0200 ---------------------------------------------------------------------- jaas/modules/pom.xml | 14 +- .../modules/syncope/SyncopeBackingEngine.java | 175 +++++++++++++++++++ .../syncope/SyncopeBackingEngineFactory.java | 51 ++++++ .../modules/syncope/SyncopeLoginModule.java | 154 ++++++++++++++++ .../modules/syncope/SyncopeLoginModuleTest.java | 105 +++++++++++ .../developers-guide/security-framework.conf | 49 ++++++ 6 files changed, 547 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/855d1983/jaas/modules/pom.xml ---------------------------------------------------------------------- diff --git a/jaas/modules/pom.xml b/jaas/modules/pom.xml index 3ebf7f7..c645957 100644 --- a/jaas/modules/pom.xml +++ b/jaas/modules/pom.xml @@ -53,6 +53,13 @@ </dependency> <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.3.5</version> + <scope>provided</scope> + </dependency> + + <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.fileinstall</artifactId> </dependency> @@ -86,6 +93,7 @@ <artifactId>org.apache.aries.blueprint.core</artifactId> <scope>provided</scope> </dependency> + <dependency> <groupId>org.apache.directory.server</groupId> <artifactId>apacheds-core-integ</artifactId> @@ -126,10 +134,14 @@ javax.net, org.apache.karaf.jaas.config, org.apache.aries.blueprint.ext, + !net.sf.ehcache*, + !net.spy.memcached*, * </Import-Package> <Private-Package> - org.apache.felix.utils* + org.apache.felix.utils*, + org.apache.http*, + org.apache.commons.codec* </Private-Package> </instructions> </configuration> http://git-wip-us.apache.org/repos/asf/karaf/blob/855d1983/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngine.java ---------------------------------------------------------------------- diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngine.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngine.java new file mode 100644 index 0000000..0579914 --- /dev/null +++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngine.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.karaf.jaas.modules.syncope; + +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.apache.karaf.jaas.boot.principal.GroupPrincipal; +import org.apache.karaf.jaas.boot.principal.RolePrincipal; +import org.apache.karaf.jaas.boot.principal.UserPrincipal; +import org.apache.karaf.jaas.modules.BackingEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; + +public class SyncopeBackingEngine implements BackingEngine { + + private final Logger logger = LoggerFactory.getLogger(SyncopeBackingEngine.class); + + private String address; + + private DefaultHttpClient client; + + public SyncopeBackingEngine(String address, String adminUser, String adminPassword) { + this.address = address; + + client = new DefaultHttpClient(); + Credentials creds = new UsernamePasswordCredentials(adminUser, adminPassword); + client.getCredentialsProvider().setCredentials(AuthScope.ANY, creds); + } + + public void addUser(String username, String password) { + if (username.startsWith(GROUP_PREFIX)) { + throw new IllegalArgumentException("Group prefix " + GROUP_PREFIX + " not permitted with Syncope backend"); + } + HttpPost request = new HttpPost(address + "/users"); + String userTO = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + + "<user>" + + "<attributes>" + + "<attribute><readonly>false</readonly><schema>fullname</schema><value>" + username + "</value></attribute>" + + "<attribute><readonly>false</readonly><schema>surname</schema><value>" + username + "</value></attribute>" + + "<attribute><readonly>false</readonly><schema>userId</schema><value>" + username + "@karaf.apache.org</value></attribute>" + + "</attributes>" + + "<password>" + password + "</password>" + + "<username>" + username + "</username>" + + "</user>"; + try { + StringEntity entity = new StringEntity(userTO); + request.setEntity(entity); + HttpResponse response = client.execute(request); + } catch (Exception e) { + logger.error("Can't add user {}", username, e); + throw new RuntimeException("Can't add user " + username, e); + } + } + + public void deleteUser(String username) { + if (username.startsWith(GROUP_PREFIX)) { + throw new IllegalArgumentException("Group prefix " + GROUP_PREFIX + " not permitted with Syncope backend"); + } + HttpDelete request = new HttpDelete(address + "/users/" + username); + try { + client.execute(request); + } catch (Exception e) { + logger.error("Can't delete user {}", username, e); + throw new RuntimeException("Can't delete user " + username, e); + } + } + + public List<UserPrincipal> listUsers() { + List<UserPrincipal> users = new ArrayList<UserPrincipal>(); + HttpGet request = new HttpGet(address + "/users"); + try { + HttpResponse response = client.execute(request); + String responseTO = EntityUtils.toString(response.getEntity()); + if (responseTO != null && !responseTO.isEmpty()) { + // extracting the user + int index = responseTO.indexOf("<username>"); + while (index != -1) { + responseTO = responseTO.substring(index + "<username>".length()); + int end = responseTO.indexOf("</username>"); + if (end == -1) { + index = -1; + } + String username = responseTO.substring(0, end); + users.add(new UserPrincipal(username)); + responseTO = responseTO.substring(end + "</username>".length()); + index = responseTO.indexOf("<username>"); + } + } + } catch (Exception e) { + throw new RuntimeException("Error listing users", e); + } + return users; + } + + public List<RolePrincipal> listRoles(Principal principal) { + List<RolePrincipal> roles = new ArrayList<RolePrincipal>(); + HttpGet request = new HttpGet(address + "/users?username=" + principal.getName()); + try { + HttpResponse response = client.execute(request); + String responseTO = EntityUtils.toString(response.getEntity()); + if (responseTO != null && !responseTO.isEmpty()) { + int index = responseTO.indexOf("<roleName>"); + while (index != 1) { + responseTO = responseTO.substring(index + "<roleName>".length()); + int end = responseTO.indexOf("</roleName>"); + if (end == -1) { + index = -1; + break; + } + String role = responseTO.substring(0, end); + roles.add(new RolePrincipal(role)); + responseTO = responseTO.substring(end + "</roleName>".length()); + index = responseTO.indexOf("<roleName>"); + } + } + } catch (Exception e) { + throw new RuntimeException("Error listing roles", e); + } + return roles; + } + + public void addRole(String username, String role) { + throw new RuntimeException("Roles management should be done on the Syncope side"); + } + + public void deleteRole(String username, String role) { + throw new RuntimeException("Roles management should be done on the Syncope side"); + } + + public List<GroupPrincipal> listGroups(UserPrincipal principal) { + return new ArrayList<GroupPrincipal>(); + } + + public void addGroup(String username, String group) { + throw new RuntimeException("Group management is not supported by Syncope backend"); + } + + public void deleteGroup(String username, String group) { + throw new RuntimeException("Group management is not supported by Syncope backend"); + } + + public void addGroupRole(String group, String role) { + throw new RuntimeException("Group management is not supported by Syncope backend"); + } + + public void deleteGroupRole(String group, String role) { + throw new RuntimeException("Group management is not supported by Syncope backend"); + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/855d1983/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngineFactory.java ---------------------------------------------------------------------- diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngineFactory.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngineFactory.java new file mode 100644 index 0000000..6a72677 --- /dev/null +++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeBackingEngineFactory.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.karaf.jaas.modules.syncope; + +import org.apache.karaf.jaas.modules.BackingEngine; +import org.apache.karaf.jaas.modules.BackingEngineFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class SyncopeBackingEngineFactory implements BackingEngineFactory { + + private static final Logger LOGGER = LoggerFactory.getLogger(SyncopeBackingEngineFactory.class); + + public BackingEngine build(Map options) { + SyncopeBackingEngine instance = null; + String address = (String) options.get(SyncopeLoginModule.ADDRESS); + String adminUser = (String) options.get(SyncopeLoginModule.ADMIN_USER); + String adminPassword = (String) options.get(SyncopeLoginModule.ADMIN_PASSWORD); + + try { + instance = new SyncopeBackingEngine(address, adminUser, adminPassword); + } catch (Exception e) { + LOGGER.error("Error creating the Syncope backing engine", e); + } + + return instance; + } + + /** + * Returns the login module class, that this factory can build. + */ + public String getModuleClass() { + return SyncopeLoginModule.class.getName(); + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/855d1983/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModule.java ---------------------------------------------------------------------- diff --git a/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModule.java b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModule.java new file mode 100644 index 0000000..47cbd0f --- /dev/null +++ b/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModule.java @@ -0,0 +1,154 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package org.apache.karaf.jaas.modules.syncope; + +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.apache.karaf.jaas.boot.principal.RolePrincipal; +import org.apache.karaf.jaas.boot.principal.UserPrincipal; +import org.apache.karaf.jaas.modules.AbstractKarafLoginModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.security.auth.Subject; +import javax.security.auth.callback.*; +import javax.security.auth.login.LoginException; +import java.io.IOException; +import java.security.Principal; +import java.util.*; + +/** + * Karaf login module which uses Apache Syncope backend. + */ +public class SyncopeLoginModule extends AbstractKarafLoginModule { + + private final static Logger LOGGER = LoggerFactory.getLogger(SyncopeLoginModule.class); + + public final static String ADDRESS = "address"; + public final static String ADMIN_USER = "admin.user"; // for the backing engine + public final static String ADMIN_PASSWORD = "admin.password"; // for the backing engine + + private String address; + + public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { + super.initialize(subject, callbackHandler, options); + address = (String) options.get(ADDRESS); + } + + public boolean login() throws LoginException { + Callback[] callbacks = new Callback[2]; + callbacks[0] = new NameCallback("Username: "); + callbacks[1] = new PasswordCallback("Password: ", false); + + try { + callbackHandler.handle(callbacks); + } catch (IOException ioException) { + throw new LoginException(ioException.getMessage()); + } catch (UnsupportedCallbackException unsupportedCallbackException) { + throw new LoginException(unsupportedCallbackException.getMessage() + " not available to obtain information from user."); + } + + user = ((NameCallback) callbacks[0]).getName(); + + char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword(); + if (tmpPassword == null) { + tmpPassword = new char[0]; + } + String password = new String(tmpPassword); + principals = new HashSet<Principal>(); + + // authenticate the user on Syncope + LOGGER.debug("Authenticate user {} on Syncope located {}", user, address); + DefaultHttpClient client = new DefaultHttpClient(); + Credentials creds = new UsernamePasswordCredentials(user, password); + client.getCredentialsProvider().setCredentials(AuthScope.ANY, creds); + HttpGet get = new HttpGet(address + "/users/self"); + List<String> roles = new ArrayList<String>(); + try { + CloseableHttpResponse response = client.execute(get); + LOGGER.debug("Syncope HTTP response status code: {}", response.getStatusLine().getStatusCode()); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + LOGGER.warn("User {} not authenticated", user); + return false; + } + LOGGER.debug("User {} authenticated", user); + LOGGER.debug("Populating principals with user"); + principals.add(new UserPrincipal(user)); + LOGGER.debug("Retrieving user {} roles", user); + roles = extractingRoles(EntityUtils.toString(response.getEntity())); + } catch (Exception e) { + LOGGER.error("User {} authentication failed", user, e); + throw new LoginException("User " + user + " authentication failed: " + e.getMessage()); + } + + LOGGER.debug("Populating principals with roles"); + for (String role : roles) { + principals.add(new RolePrincipal(role)); + } + + return true; + } + + /** + * Extract the user roles from the Syncope entity response. + * + * @param response the HTTP response from Syncope. + * @return the list of user roles. + * @throws Exception in case of extraction failure. + */ + protected List<String> extractingRoles(String response) throws Exception { + List<String> roles = new ArrayList<String>(); + if (response != null && !response.isEmpty()) { + // extract the <memberships> element + int index = response.indexOf("<memberships>"); + response = response.substring(index + "<memberships>".length()); + index = response.indexOf("</memberships>"); + response = response.substring(0, index); + + // looking for the roleName elements + index = response.indexOf("<roleName>"); + while (index != -1) { + response = response.substring(index + "<roleName>".length()); + int end = response.indexOf("</roleName>"); + if (end == -1) { + index = -1; + } + String role = response.substring(0, end); + roles.add(role); + response = response.substring(end + "</roleName>".length()); + index = response.indexOf("<roleName>"); + } + + } + return roles; + } + + public boolean abort() { + return true; + } + + public boolean logout() throws LoginException { + subject.getPrincipals().removeAll(principals); + principals.clear(); + return true; + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/855d1983/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModuleTest.java ---------------------------------------------------------------------- diff --git a/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModuleTest.java b/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModuleTest.java new file mode 100644 index 0000000..eca0818 --- /dev/null +++ b/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/syncope/SyncopeLoginModuleTest.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.karaf.jaas.modules.syncope; + +import org.junit.Test; +import org.junit.Assert; + +import java.util.List; + +public class SyncopeLoginModuleTest { + + @Test + public void testRolesExtraction() throws Exception { + String syncopeResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + + "<user>\n" + + " <attributes>\n" + + " <attribute>\n" + + " <readonly>false</readonly>\n" + + " <schema>cool</schema>\n" + + " <value>false</value>\n" + + " </attribute>\n" + + " <attribute>\n" + + " <readonly>false</readonly>\n" + + " <schema>email</schema>\n" + + " <value>[email protected]</value>\n" + + " </attribute>\n" + + " <attribute>\n" + + " <readonly>false</readonly>\n" + + " <schema>fullname</schema>\n" + + " <value>karaf</value>\n" + + " </attribute>\n" + + " <attribute>\n" + + " <readonly>false</readonly>\n" + + " <schema>gender</schema>\n" + + " <value>M</value>\n" + + " </attribute>\n" + + " <attribute>\n" + + " <readonly>false</readonly>\n" + + " <schema>surname</schema>\n" + + " <value>karaf</value>\n" + + " </attribute>\n" + + " <attribute>\n" + + " <readonly>false</readonly>\n" + + " <schema>userId</schema>\n" + + " <value>[email protected]</value>\n" + + " </attribute>\n" + + " </attributes>\n" + + " <derivedAttributes/>\n" + + " <id>100</id>\n" + + " <propagationStatuses/>\n" + + " <resources/>\n" + + " <virtualAttributes/>\n" + + " <creationDate>2014-08-12T18:37:09.202+02:00</creationDate>\n" + + " <failedLogins>0</failedLogins>\n" + + " <lastLoginDate>2014-08-13T09:38:02.204+02:00</lastLoginDate>\n" + + " <memberships>\n" + + " <membership>\n" + + " <attributes/>\n" + + " <derivedAttributes/>\n" + + " <id>100</id>\n" + + " <propagationStatuses/>\n" + + " <resources/>\n" + + " <virtualAttributes/>\n" + + " <resources/>\n" + + " <roleId>100</roleId>\n" + + " <roleName>admin</roleName>\n" + + " </membership>\n" + + " <membership>\n" + + " <attributes/>\n" + + " <derivedAttributes/>\n" + + " <id>101</id>\n" + + " <propagationStatuses/>\n" + + " <resources/>\n" + + " <virtualAttributes/>\n" + + " <resources/>\n" + + " <roleId>101</roleId>\n" + + " <roleName>another</roleName>\n" + + " </membership>\n" + + " </memberships>\n" + + " <password>36460D3A3C1E27C0DB2AF23344475EE712DD3C9D</password>\n" + + " <status>active</status>\n" + + " <username>karaf</username>\n" + + "</user>\n"; + SyncopeLoginModule syncopeLoginModule = new SyncopeLoginModule(); + List<String> roles = syncopeLoginModule.extractingRoles(syncopeResponse); + Assert.assertEquals(2, roles.size()); + Assert.assertEquals("admin", roles.get(0)); + Assert.assertEquals("another", roles.get(1)); + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/855d1983/manual/src/main/webapp/developers-guide/security-framework.conf ---------------------------------------------------------------------- diff --git a/manual/src/main/webapp/developers-guide/security-framework.conf b/manual/src/main/webapp/developers-guide/security-framework.conf index 09b1f5c..57352db 100644 --- a/manual/src/main/webapp/developers-guide/security-framework.conf +++ b/manual/src/main/webapp/developers-guide/security-framework.conf @@ -270,6 +270,55 @@ The LDAPLoginModule supports the following patterns that you can use in the filt * {{%fqdn}} is replaced by the user full qualified DN ({{userDN,userBaseDN}}). * {{%nsdn}} is replaced by the userDNNamespace (interesting especially for ActiveDirectory). +h3. SyncopeLoginModule + +The Syncope login module uses the Syncope REST API to authenticate users and retrieve the roles. + +The Syncope login module just requires one parameter: + +|| Name || Description || +| {{address}} | Location of the Syncope REST API | +| {{admin.user}} | Admin username to administrate Syncope (only required by the backend engine) | +| {{admin.password}} | Admin password to administrate Syncope (only required by the backend engine) | + +The following snippet shows how to use Syncope with the karaf realm: + +{code} +<jaas:config name="karaf" rank="2"> + <jaas:module className="org.apache.karaf.jaas.modules.syncope.SyncopeLoginModule" flags="required"> + address=http://localhost:9080/syncope/cxf + admin.user=admin + admin.password=password + </jaas:module> +</jaas:config> +{code} + +SyncopeLoginModule comes with a backend engine allowing to manipulate users and roles. You have to register the +SyncopeBackendEngineFactory service. +For instance, the following blueprint descriptor enables the SyncopeLoginModule and the backend engine factory: + +{code} +<?xml version="1.0" encoding="UTF-8"?> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:jaas="http://karaf.apache.org/xmlns/jaas/v1.1.0" + xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"> + + <jaas:config name="karaf" rank="2"> + <jaas:module className="org.apache.karaf.jaas.modules.syncope.SyncopeLoginModule" + flags="required"> + address=http://localhost:9080/syncope/cxf + admin.user=admin + admin.password=password + </jaas:module> + </jaas:config> + + <service interface="org.apache.karaf.jaas.modules.BackingEngineFactory"> + <bean class="org.apache.karaf.jaas.modules.syncope.SyncopeBackingEngineFactory"/> + </service> + +</blueprint> +{code} + h2. Encryption service The [EncryptionService|http://svn.apache.org/repos/asf/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/EncryptionService.java] is a service registered in the OSGi registry providing means to encrypt and check encrypted passwords. This service acts as a factory for [Encryption|http://svn.apache.org/repos/asf/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/Encryption.java] objects actually performing the encryption.
