All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavemaker.runtime.security.SecurityService Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2022-2023 WaveMaker, 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 com.wavemaker.runtime.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import com.wavemaker.commons.util.EncodeUtils;
import com.wavemaker.runtime.commons.WMAppContext;
import com.wavemaker.runtime.security.config.WMAppSecurityConfig;
import com.wavemaker.runtime.security.model.SecurityInfo;
import com.wavemaker.runtime.security.model.UserInfo;
import com.wavemaker.app.security.models.CSRFConfig;
import com.wavemaker.app.security.models.LoginConfig;
import com.wavemaker.app.security.models.RoleConfig;
import com.wavemaker.app.security.models.RolesConfig;
import com.wavemaker.runtime.security.token.Token;
import com.wavemaker.runtime.security.token.WMTokenBasedAuthenticationService;

/**
 * The Security Service provides interfaces to access authentication and authorization information in the system.
 *
 * @author Frankie Fu
 */
@Service
public class SecurityService {

    private static final Logger logger = LoggerFactory.getLogger(SecurityService.class);

    private static final String ROLE_PREFIX = "ROLE_";

    private Boolean securityEnabled;

    @Autowired(required = false)
    private WMTokenBasedAuthenticationService wmTokenBasedAuthenticationService;

    @Autowired(required = false)
    private WMAppSecurityConfig wmAppSecurityConfig;

    /**
     * This method is deprecated. You can set custom attributes in successhandlers.
     */
    @Deprecated
    public static int getTenantId() {
        return 0;
    }

    /**
     * Checks whether the security is enabled or not. It returns true if it is enable, else, false.
     *
     * @return true if the security is enabled; otherwise, false.
     */
    public boolean isSecurityEnabled() {
        if (securityEnabled == null) {
            if (wmAppSecurityConfig != null) {
                securityEnabled = wmAppSecurityConfig.isEnforceSecurity();
            } else {
                securityEnabled = false;
            }
        }
        return securityEnabled;
    }

    private boolean isRememberMeEnabled() {
        if (wmAppSecurityConfig != null && wmAppSecurityConfig.getRememberMeConfig() != null) {
            return wmAppSecurityConfig.getRememberMeConfig().isEnabled();
        }
        return false;
    }

    public LoginConfig getLoginConfig() {
        return wmAppSecurityConfig.getLoginConfig();
    }

    /**
     * Checks whether the user has been authenticated or not depending on authentication object.
     *
     * @return true if the user was authenticated; otherwise, false.
     */
    public boolean isAuthenticated() {
        return getAuthenticatedAuthentication() != null;
    }

    public Map getClientAttributes() {
        Authentication authentication = getAuthenticatedAuthentication();

        if (authentication != null) {
            WMAuthentication wmAuthentication = (WMAuthentication) authentication;
            Map customAttributes = new HashMap<>();
            Map attributeMap = wmAuthentication.getAttributes();
            attributeMap.entrySet().stream().forEach(entry -> {
                    Attribute attribute = entry.getValue();
                    if (attribute.getScope() != Attribute.AttributeScope.SERVER_ONLY) {
                        customAttributes.put(entry.getKey(), attribute.getValue());
                    }
                }
            );
            return customAttributes;
        }
        return null;
    }

    public Map getAllAttributes() {
        Authentication authentication = getAuthenticatedAuthentication();

        if (authentication != null) {
            WMAuthentication wmAuthentication = (WMAuthentication) authentication;
            Map customAttributes = new HashMap<>();
            Map attributeMap = wmAuthentication.getAttributes();
            attributeMap.entrySet().stream().forEach(entry -> {
                    Attribute attribute = entry.getValue();
                    customAttributes.put(entry.getKey(), attribute.getValue());
                }
            );
            return customAttributes;
        }
        return null;
    }

    public boolean addAttribute(String key, Object value, Attribute.AttributeScope attributeScope) {
        Authentication authentication = getAuthenticatedAuthentication();
        if (authentication != null) {
            WMAuthentication wmAuthentication = (WMAuthentication) authentication;
            wmAuthentication.addAttribute(key, value, attributeScope);
            return true;
        }
        return false;
    }

    /**
     * Get Current LoggedIn User.
     * If security is enabled and user is authenticated then other fields like userId,
     * userName, tenantId, userRoles etc are also set, otherwise, only securityEnabled value is set.
     *
     * @return WMCurrentUser type.
     */
    public WMCurrentUser getLoggedInUser() {
        WMCurrentUser wmCurrentUser = new WMCurrentUser();
        boolean securityEnabled = isSecurityEnabled();
        boolean authenticated = isAuthenticated();
        wmCurrentUser.setSecurityEnabled(securityEnabled);
        wmCurrentUser.setAuthenticated(authenticated);
        if (securityEnabled && authenticated) {
            wmCurrentUser.setUserId(getUserId());
            wmCurrentUser.setUserName(getUserName());
            wmCurrentUser.setUserRoles(getUserRoles());
            wmCurrentUser.setLoginTime(getLoginTime());
        }
        return wmCurrentUser;
    }

    /**
     * Returns the user name of the principal in the current security context.
     * If the {@link org.springframework.security.core.userdetails.UserDetails} obtained from authentication is an instance of {@link WMUserDetails},then user's long name is returned from WMUserDetails,
     * else returns the username from authentication Object.
     * Second case happens when services like ldap are used to authenticate
     *
     * @return The user name.
     */
    public String getUserName() {
        final Authentication authentication = getAuthenticatedAuthentication();
        if (authentication != null) {
            return authentication.getName();
        }
        return null;
    }

    /**
     * Returns the user id of the principal in the current security context, otherwise, it returns name of the authenticated user..
     *
     * @return String value, which will contain userId.
     */
    public String getUserId() {
        final Authentication authentication = getAuthenticatedAuthentication();
        if (authentication != null) {
            return ((WMAuthentication) authentication).getUserId();
        }
        return null;
    }

    /**
     * If authentication is null then it returns empty String array. If not then it will retrieve the authority and process the roleName in the spring format before returning and then return.
     *
     * @return String array with roles or empty depending on authentication object.
     */
    public String[] getUserRoles() {
        Authentication authentication = getAuthenticatedAuthentication();
        if (authentication == null) {
            return new String[0];
        }
        Collection authorities = authentication.getAuthorities();
        List roleNames = new ArrayList<>();
        for (GrantedAuthority authority : authorities) {
            String roleName = authority.getAuthority();
            String realRoleName = null;
            if (roleName.startsWith(ROLE_PREFIX)) {
                // take out the prefix and get the actual role name
                realRoleName = roleName.substring(ROLE_PREFIX.length());
            } else {
                logger.warn("Role {} does not use the prefix {}. This may cause problems", roleName, ROLE_PREFIX);
                realRoleName = roleName;
            }

            // make sure the role is not the maker for no roles
            if (realRoleName != null) {
                roleNames.add(EncodeUtils.decode(realRoleName));
            }
        }

        return roleNames.toArray(new String[0]);
    }

    /**
     * If authentication is null then it returns empty String array. If not then it will retrieve the authority and process the roleName in the spring format before returning and then return.
     *
     * @return String array with roles or empty depending on authentication object.
     */
    public String getUserLandingPage() {
        String landingPage = null;

        String[] userRoles = getUserRoles();
        if (userRoles.length > 0) {
            RolesConfig rolesConfig = wmAppSecurityConfig.getRolesConfig();
            if (rolesConfig != null) {
                Map roleMap = rolesConfig.getRoleMap();

                if (userRoles.length == 1) {
                    final RoleConfig roleConfig = roleMap.get(userRoles[0]);
                    if (roleConfig != null) {
                        landingPage = roleConfig.getLandingPage();
                    }
                } else {
                    Iterator> roleEntryIterator = roleMap.entrySet().iterator();
                    while (roleEntryIterator.hasNext() && landingPage == null) {
                        Map.Entry roleEntry = roleEntryIterator.next();
                        for (String userRole : userRoles) {
                            if (userRole.equals(roleEntry.getKey())) {
                                landingPage = roleEntry.getValue().getLandingPage();
                                break;
                            }
                        }
                    }
                }
            }
        }
        return landingPage;
    }

    /**
     * It returns Login Time of the current user when userDetail object in current security context is not null, otherwise, it returns 0.
     *
     * @return login tine in milliseconds (long value).
     */
    public long getLoginTime() {
        final Authentication authentication = getAuthenticatedAuthentication();
        if (authentication != null) {
            return ((WMAuthentication) authentication).getLoginTime();
        }
        return 0L;
    }

    public List getRoles() {
        RolesConfig rolesConfig = wmAppSecurityConfig.getRolesConfig();
        return (rolesConfig == null) ? Collections.emptyList() : new ArrayList<>(rolesConfig.getRoleMap().keySet());
    }

    public SecurityInfo getSecurityInfo() {
        final boolean authenticated = isAuthenticated();
        UserInfo userInfo = null;
        if (authenticated) {
            userInfo = new UserInfo();
            userInfo.setUserId(getUserId());
            userInfo.setUserName(getUserName());
            userInfo.setUserRoles(getUserRoles());
            userInfo.setLandingPage(getUserLandingPage());
            userInfo.setUserAttributes(getClientAttributes());
        }
        SecurityInfo securityInfo = getAppSecurityInfo();
        securityInfo.setAuthenticated(authenticated);
        securityInfo.setUserInfo(userInfo);
        return securityInfo;
    }

    public SecurityInfo getAppSecurityInfo() {
        SecurityInfo securityInfo = new SecurityInfo();
        securityInfo.setSecurityEnabled(isSecurityEnabled());
        securityInfo.setRememberMeEnabled(isRememberMeEnabled());
        securityInfo.setLoginConfig(getLoginConfig());
        securityInfo.setCsrfHeaderName(getCsrfHeaderName());
        securityInfo.setCsrfCookieName(getCsrfCookieName());
        return securityInfo;
    }

    public Token generateUserAccessToken() {
        Authentication authentication = getAuthenticatedAuthentication();
        if (authentication != null) {
            if (wmTokenBasedAuthenticationService == null) {
                throw new AuthenticationServiceException("Token based Security is not enabled");
            }
            return wmTokenBasedAuthenticationService.generateToken(authentication);
        }
        throw new AuthenticationCredentialsNotFoundException("Require authentication to generate access token");
    }

    public void ssoLogin() {
        //DUMMY METHOD to redirect to default sso entry point...
        //When this method is invoked, the sso Filter is intercepted and sends the user to the default sso Login page through its AuthenticationEntryPoint.
    }

    private static Authentication getAuthenticatedAuthentication() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication instanceof AnonymousAuthenticationToken ? null : authentication;
    }

    private String getCsrfCookieName() {
        if (isSecurityEnabled()) {
            CSRFConfig csrfConfig = WMAppContext.getInstance().getSpringBean(CSRFConfig.class);
            return csrfConfig.getCookieName();
        }
        return null;
    }

    private String getCsrfHeaderName() {
        if (isSecurityEnabled()) {
            CSRFConfig csrfConfig = WMAppContext.getInstance().getSpringBean(CSRFConfig.class);
            return csrfConfig.getHeaderName();
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy