/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * 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.kie.server.services.impl.security.adapters; import java.io.IOException; import java.security.Principal; import java.security.acl.Group; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.ServiceLoader; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginContext; import javax.security.sasl.RealmCallback; import org.kie.server.api.KieServerConstants; import org.kie.server.api.security.SecurityAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JMSSecurityAdapter implements SecurityAdapter { private static final Logger logger = LoggerFactory.getLogger(JMSSecurityAdapter.class); private static final ServiceLoader<SecurityAdapter> securityAdapters = ServiceLoader.load(SecurityAdapter.class); private static List<SecurityAdapter> adapters = new ArrayList<>(); private static ThreadLocal<UserDetails> currentUser = new ThreadLocal<UserDetails>(); static { for (SecurityAdapter adapter : securityAdapters) { adapters.add(adapter); } } @Override public String getUser(Object ... params) { if (currentUser.get() != null) { logger.debug("Returning name from JMS Adapter - {}", currentUser.get().getName()); return currentUser.get().getName(); } return null; } @Override public List<String> getRoles(Object ... params) { if (currentUser.get() != null) { logger.debug("Returning name from JMS Adapter - {}", currentUser.get().getName()); return currentUser.get().getRoles(); } return Collections.emptyList(); } public static void login(String user, String pass) { if (currentUser.get() != null) { logger.debug("Already authenticated with user {}", currentUser.get().getName()); return; } logger.debug("About to login as {} with pass {}", user, pass.length()); try { CallbackHandler handler = new UserPassCallbackHandler(user, pass); final String domain = System.getProperty(KieServerConstants.KIE_SERVER_JAAS_DOMAIN, "kie-jms-login-context"); LoginContext lc = new LoginContext( domain, handler); lc.login(); Subject subject = lc.getSubject(); logger.debug("Login successfull and subject is {}", subject); UserDetails userDetails = new UserDetails(); userDetails.setName(user); List<String> roles = new ArrayList<String>(); if (subject != null) { Set<Principal> principals = subject.getPrincipals(); if (principals != null) { roles = new ArrayList<String>(); for (Principal principal : principals) { if (principal instanceof Group) { Enumeration<? extends Principal> groups = ((Group) principal).members(); while (groups.hasMoreElements()) { Principal groupPrincipal = (Principal) groups.nextElement(); roles.add(groupPrincipal.getName()); } break; } } } roles.addAll(getRolesFromAdapter(subject)); } userDetails.setRoles(roles); logger.debug("setting user details as {}", userDetails); currentUser.set(userDetails); } catch( Exception e ) { logger.debug( "Unable to login via JAAS with message supplied user and password", e); } } public static void logout() { currentUser.set(null); } private static class UserDetails { private String name; private List<String> roles; public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getRoles() { return roles; } public void setRoles(List<String> roles) { this.roles = roles; } @Override public String toString() { return "UserDetails{" + "name='" + name + '\'' + ", roles=" + roles + '}'; } } private static class UserPassCallbackHandler implements CallbackHandler { private String user; private String pass; public UserPassCallbackHandler(String user, String pass) { this.user = user; this.pass = pass; } @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback current : callbacks) { if (current instanceof NameCallback) { NameCallback ncb = (NameCallback) current; ncb.setName(user); } else if (current instanceof PasswordCallback) { PasswordCallback pcb = (PasswordCallback) current; pcb.setPassword(pass.toCharArray()); } else if (current instanceof RealmCallback) { RealmCallback realmCallback = (RealmCallback) current; realmCallback.setText(realmCallback.getDefaultText()); } } } } protected static List<String> getRolesFromAdapter(Subject subject) { List<String> roles = new ArrayList<String>(); for (SecurityAdapter adapter : adapters) { List<String> adapterRoles = adapter.getRoles(subject); if (adapterRoles != null && !adapterRoles.isEmpty()) { roles.addAll(adapterRoles); } } return roles; } }