/* * 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 javax.naming.OperationNotSupportedException; import java.security.Principal; import java.util.ArrayList; import java.util.List; import java.util.Map; 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"); request.setHeader("Content-Type", "application/xml"); 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); request.setHeader("Content-Type", "application/xml"); 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<>(); HttpGet request = new HttpGet(address + "/users"); request.setHeader("Content-Type", "application/xml"); 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<>(); HttpGet request = new HttpGet(address + "/users?username=" + principal.getName()); request.setHeader("Content-Type", "application/xml"); 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"); } public Map<GroupPrincipal, String> listGroups() { throw new RuntimeException("Group management is not supported by Syncope backend"); } public void createGroup(String group) { throw new RuntimeException("Group management is not supported by Syncope backend"); } }