• Saiku登录源码追踪.(十三)


    Saiku登录源码追踪呀~

    >>首先我们需要debug跟踪saiku登录执行的源码信息

    saiku源码的debug方式上一篇博客已有说明,这里简单介绍一下

    在saiku启动脚本中添加如下命令: (windows下: start-saiku.bat)

    set CATALINA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n  (后面可能还会有一些JVM参数信息)

    使用Eclipse打开saiku源码  -- > Eclipse工具栏中的 Run  --> Debug configurations --> Remote Java Application --> 选中对应的源码项目(saiku-web),远程访问saiku的ip,以及脚本中指定监听的端口 (address) 8787  --> Debug

    在浏览器中根据saiku地址信息访问saiku,输入用户名以及密码信息登录,Eclipse则会进入对应的debug阶段。 

    >>源码追踪

    1.首先会调用 saiku-web项目  org.saiku.web.rest.resources 包下的 SessionResource中的登录方法

    sessionService.login(res,username,password)

    /**
     * Saiku Session Endpoints
     */
    @Component
    @Path("/saiku/session")
    public class SessionResource  {
    
      /*此处省略其他代码信息*/
    
      private ISessionService sessionService;
    
      /**
       * Login to Saiku
       * @summary Login
       * @param req Servlet request
       * @param username Username
       * @param password Password
       * @return A 200 response
       */
        @POST
    	@Consumes("application/x-www-form-urlencoded")
    	public Response login(
    			@Context HttpServletRequest req,
    			@FormParam("username") String username, 
    			@FormParam("password") String password) 
    	{
    		try {
    		  sessionService.login(req, username, password);
    		  return Response.ok().build();
    		}
    		catch (Exception e) {
    			log.debug("Error logging in:" + username, e);
    			return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getLocalizedMessage()).build();
    		}
    	}
    }
    

      

    2.进入org.saiku.web.service 包下的 SessionService类中的 sessionService.login(res,username,password)方法 

    进行认证的方法主要是:    authenticate(req, username, password);

    package org.saiku.web.service;
    /*此处省略了导入相关包信息*/
    public class SessionService implements ISessionService { /**此处省略其他代码*/ /* (non-Javadoc) * @see org.saiku.web.service.ISessionService#login(javax.servlet.http.HttpServletRequest, java.lang.String, java.lang.String) */ public Map<String, Object> login(HttpServletRequest req, String username, String password ) throws LicenseException { Object sl = null; String notice = null; HttpSession session = ((HttpServletRequest)req).getSession(true); session.getId(); sessionRepo.setSession(session); try { sl = l.getLicense(); } catch (Exception e) { log.debug("Could not process license", e); throw new LicenseException("Error fetching license. Get a free license from http://licensing.meteorite.bi. You can upload it at /upload.html"); } if (sl != null) { try { l.validateLicense(); } catch (RepositoryException | IOException | ClassNotFoundException e) { log.debug("Repository Exception, couldn't get license", e); throw new LicenseException("Error fetching license. Please check your logs."); } try { if (l.getLicense() instanceof SaikuLicense2) { if (authenticationManager != null) { authenticate(req, username, password); } if (SecurityContextHolder.getContext() != null && SecurityContextHolder.getContext().getAuthentication() != null) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (authorisationPredicate.isAuthorised(auth)) { Object p = auth.getPrincipal(); createSession(auth, username, password); return sessionHolder.get(p); } else { log.info(username + " failed authorisation. Rejecting login"); throw new RuntimeException("Authorisation failed for: " + username); } } return new HashMap<>(); } } catch (IOException | ClassNotFoundException | RepositoryException e) { log.debug("Repository Exception, couldn't get license", e); throw new LicenseException("Error fetching license. Please check your logs."); } } return null; } }

      

    3.继续进入SessionService的 authenticate (req,username,password)方法进行认证

    主要认证:  Authentication authentication = this.authenticationManager.authenticate(token);

    /* (non-Javadoc)
    	 * @see org.saiku.web.service.ISessionService#authenticate(javax.servlet.http.HttpServletRequest, java.lang.String, java.lang.String)
    	 */
    	public void authenticate(HttpServletRequest req, String username, String password) {
    		try {
    			UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
    			token.setDetails(new WebAuthenticationDetails(req));
    			Authentication authentication = this.authenticationManager.authenticate(token);
    			log.debug("Logging in with [{}]", authentication.getPrincipal());
    			SecurityContextHolder.getContext().setAuthentication(authentication);
    		}
    		catch (BadCredentialsException bd) {
    			throw new RuntimeException("Authentication failed for: " + username, bd);
    		}
    
    	}
    

      

    4.转入spring-security认证框架中的 org.springframework.security.authentication包下的ProviderManager类中的  this.authenticationManager.authenticate(token)方法

    主要认证: result = provider.authenticate(authentication);

    	/**
    	 * Attempts to authenticate the passed {@link Authentication} object.
    	 * <p>
    	 * The list of {@link AuthenticationProvider}s will be successively tried until an
    	 * <code>AuthenticationProvider</code> indicates it is capable of authenticating the
    	 * type of <code>Authentication</code> object passed. Authentication will then be
    	 * attempted with that <code>AuthenticationProvider</code>.
    	 * <p>
    	 * If more than one <code>AuthenticationProvider</code> supports the passed
    	 * <code>Authentication</code> object, only the first
    	 * <code>AuthenticationProvider</code> tried will determine the result. No subsequent
    	 * <code>AuthenticationProvider</code>s will be tried.
    	 *
    	 * @param authentication the authentication request object.
    	 *
    	 * @return a fully authenticated object including credentials.
    	 *
    	 * @throws AuthenticationException if authentication fails.
    	 */
    	public Authentication authenticate(Authentication authentication)
    			throws AuthenticationException {
    		Class<? extends Authentication> toTest = authentication.getClass();
    		AuthenticationException lastException = null;
    		Authentication result = null;
    		boolean debug = logger.isDebugEnabled();
    
    		for (AuthenticationProvider provider : getProviders()) {
    			if (!provider.supports(toTest)) {
    				continue;
    			}
    
    			if (debug) {
    				logger.debug("Authentication attempt using "
    						+ provider.getClass().getName());
    			}
    
    			try {
    				result = provider.authenticate(authentication);
    
    				if (result != null) {
    					copyDetails(authentication, result);
    					break;
    				}
    			}
    			catch (AccountStatusException e) {
    				prepareException(e, authentication);
    				// SEC-546: Avoid polling additional providers if auth failure is due to
    				// invalid account status
    				throw e;
    			}
    			catch (InternalAuthenticationServiceException e) {
    				prepareException(e, authentication);
    				throw e;
    			}
    			catch (AuthenticationException e) {
    				lastException = e;
    			}
    		}
    
    		if (result == null && parent != null) {
    			// Allow the parent to try.
    			try {
    				result = parent.authenticate(authentication);
    			}
    			catch (ProviderNotFoundException e) {
    				// ignore as we will throw below if no other exception occurred prior to
    				// calling parent and the parent
    				// may throw ProviderNotFound even though a provider in the child already
    				// handled the request
    			}
    			catch (AuthenticationException e) {
    				lastException = e;
    			}
    		}
    
    		if (result != null) {
    			if (eraseCredentialsAfterAuthentication
    					&& (result instanceof CredentialsContainer)) {
    				// Authentication is complete. Remove credentials and other secret data
    				// from authentication
    				((CredentialsContainer) result).eraseCredentials();
    			}
    
    			eventPublisher.publishAuthenticationSuccess(result);
    			return result;
    		}
    
    		// Parent was null, or didn't authenticate (or throw an exception).
    
    		if (lastException == null) {
    			lastException = new ProviderNotFoundException(messages.getMessage(
    					"ProviderManager.providerNotFound",
    					new Object[] { toTest.getName() },
    					"No AuthenticationProvider found for {0}"));
    		}
    
    		prepareException(lastException, authentication);
    
    		throw lastException;
    	}
    

      

     5.转入 org.springframework.security.authentication.dao包下的 AbstractUserDetailsAuthenticationProvider类中的 result = provider.authenticate(authentication);

    关于密码的校验主要是:additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);

    public Authentication authenticate(Authentication authentication)
    			throws AuthenticationException {
    		Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
    				messages.getMessage(
    						"AbstractUserDetailsAuthenticationProvider.onlySupports",
    						"Only UsernamePasswordAuthenticationToken is supported"));
    
    		// Determine username
    		String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
    				: authentication.getName();
    
    		boolean cacheWasUsed = true;
    		UserDetails user = this.userCache.getUserFromCache(username);
    
    		if (user == null) {
    			cacheWasUsed = false;
    
    			try {
    				user = retrieveUser(username,
    						(UsernamePasswordAuthenticationToken) authentication);
    			}
    			catch (UsernameNotFoundException notFound) {
    				logger.debug("User '" + username + "' not found");
    
    				if (hideUserNotFoundExceptions) {
    					throw new BadCredentialsException(messages.getMessage(
    							"AbstractUserDetailsAuthenticationProvider.badCredentials",
    							"Bad credentials"));
    				}
    				else {
    					throw notFound;
    				}
    			}
    
    			Assert.notNull(user,
    					"retrieveUser returned null - a violation of the interface contract");
    		}
    
    		try {
    			preAuthenticationChecks.check(user);
    			additionalAuthenticationChecks(user,
    					(UsernamePasswordAuthenticationToken) authentication);
    		}
    		catch (AuthenticationException exception) {
    			if (cacheWasUsed) {
    				// There was a problem, so try again after checking
    				// we're using latest data (i.e. not from the cache)
    				cacheWasUsed = false;
    				user = retrieveUser(username,
    						(UsernamePasswordAuthenticationToken) authentication);
    				preAuthenticationChecks.check(user);
    				additionalAuthenticationChecks(user,
    						(UsernamePasswordAuthenticationToken) authentication);
    			}
    			else {
    				throw exception;
    			}
    		}
    

      

     6.org.springframework.security.authentication.dao包下的 DaoAuthenticationProvider 类中 additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication)方法如下

    校验密码的主要方法: passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword,salt)

    @SuppressWarnings("deprecation")
    	protected void additionalAuthenticationChecks(UserDetails userDetails,
    			UsernamePasswordAuthenticationToken authentication)
    			throws AuthenticationException {
    		Object salt = null;
    
    		if (this.saltSource != null) {
    			salt = this.saltSource.getSalt(userDetails);
    		}
    
    		if (authentication.getCredentials() == null) {
    			logger.debug("Authentication failed: no credentials provided");
    
    			throw new BadCredentialsException(messages.getMessage(
    					"AbstractUserDetailsAuthenticationProvider.badCredentials",
    					"Bad credentials"));
    		}
    
    
    		if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
    				presentedPassword, salt)) {
    			logger.debug("Authentication failed: password does not match stored value");
    
    			throw new BadCredentialsException(messages.getMessage(
    					"AbstractUserDetailsAuthenticationProvider.badCredentials",
    					"Bad credentials"));
    		}
    	}
    

      

    好了,关于saiku登录源码就追踪到这里啦~ ,到这里我们就知道怎么更改saiku对密码校验的逻辑信息啦~ 

  • 相关阅读:
    JAVA语法之小结
    JAVA之经典Student问题1
    Android之动画1
    Android之屏幕测试
    Android之点击切换图片
    Android之标签选项卡
    Android简单计算器
    Javascript之相册拖动管理
    Javascript之改变盒子颜色
    CSS之照片翻转
  • 原文地址:https://www.cnblogs.com/DFX339/p/10512522.html
Copyright © 2020-2023  润新知