/* * Copyright 2015 JBoss, by Red Hat, Inc * * 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. */ package org.uberfire.ext.security.server; import java.util.Collection; import java.util.HashSet; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.security.auth.Subject; import javax.security.jacc.PolicyContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.jboss.errai.bus.server.annotations.Service; import org.jboss.errai.security.shared.api.Role; import org.jboss.errai.security.shared.api.identity.User; import org.jboss.errai.security.shared.api.identity.UserImpl; import org.jboss.errai.security.shared.exception.FailedAuthenticationException; import org.jboss.errai.security.shared.service.AuthenticationService; import org.uberfire.backend.server.security.RoleRegistry; import org.uberfire.backend.server.security.adapter.GroupAdapterAuthorizationSource; @Service @ApplicationScoped public class ServletSecurityAuthenticationService extends GroupAdapterAuthorizationSource implements AuthenticationService { static final String USER_SESSION_ATTR_NAME = "uf.security.user"; static final String DEFAULT_ROLE_PRINCIPLE_NAME = "Roles"; private String[] rolePrincipleNames = new String[]{DEFAULT_ROLE_PRINCIPLE_NAME}; public ServletSecurityAuthenticationService() { final String value = System.getProperty("org.uberfire.security.principal.names", ""); if (value != null && !value.trim().isEmpty()) { rolePrincipleNames = value.split(","); } } protected static HttpServletRequest getRequestForThread() { HttpServletRequest request = SecurityIntegrationFilter.getRequest(); if (request == null) { throw new IllegalStateException("This service only works from threads that are handling HTTP servlet requests"); } return request; } @Override public User login(String username, String password) { final HttpServletRequest request = getRequestForThread(); try { request.login(username, password); return getUser(); } catch (final ServletException e) { throw new FailedAuthenticationException("Failed to authenticate user " + username, e); } } @Override public boolean isLoggedIn() { HttpServletRequest request = getRequestForThread(); return request.getUserPrincipal() != null; } @Override public void logout() { HttpServletRequest request = getRequestForThread(); try { request.logout(); } catch (Exception e) { } HttpSession session = request.getSession(false); if (session != null) { // The try/catch is an ugly hack for EAP 7.0.x with Keycloak (or RH-SSO) adapter. // Undertow (1.4.6-) will return what it appears to be a valid session (session != null), but in fact it // was already invalidated by the Keycloak adapter during the request.logout() call. // See https://issues.jboss.org/browse/RHBPMS-4574 try { session.invalidate(); } catch (IllegalStateException ise) { // Make sure we catch only the intended exception thrown by Undertow. Re-throw any other exception String exceptionMessage = ise.getMessage(); if (exceptionMessage == null || !exceptionMessage.contains("UT000021")) { throw ise; } } } } @Override public User getUser() { HttpServletRequest request = getRequestForThread(); if (request.getUserPrincipal() == null) { return null; } User user = null; final HttpSession session = request.getSession(); if (session != null) { user = (User) session.getAttribute(USER_SESSION_ATTR_NAME); if (user == null) { // Use roles present in the registry. final Collection<Role> userRoles = new HashSet<Role>(); for (final Role checkRole : RoleRegistry.get().getRegisteredRoles()) { if (request.isUserInRole(checkRole.getName())) { userRoles.add(checkRole); } } // Obtain roles and groups from entities present in the javax security Principal instance. final String name = request.getUserPrincipal().getName(); Subject subject = getSubjectFromPolicyContext(); List<String> principals = loadEntitiesFromSubjectAndAdapters(name, subject, rolePrincipleNames); Collection<Role> roles = getRoles(principals); if (null != roles && !roles.isEmpty()) { userRoles.addAll(roles); } Collection<org.jboss.errai.security.shared.api.Group> userGroups = getGroups(principals); // Create the user instance. user = new UserImpl(name, userRoles, userGroups); session.setAttribute(USER_SESSION_ATTR_NAME, user); } } return user; } Subject getSubjectFromPolicyContext() { Subject subject; try { subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container"); } catch (final Exception e) { subject = null; } return subject; } }