Class OAuthAuthenticatingFilter

java.lang.Object
org.apache.shiro.web.servlet.ServletContextSupport
org.apache.shiro.web.servlet.AbstractFilter
org.apache.shiro.web.servlet.NameableFilter
org.apache.shiro.web.servlet.OncePerRequestFilter
org.apache.shiro.web.servlet.AdviceFilter
org.apache.shiro.web.filter.PathMatchingFilter
org.apache.shiro.web.filter.AccessControlFilter
org.apache.shiro.web.filter.authc.AuthenticationFilter
org.apache.shiro.web.filter.authc.AuthenticatingFilter
de.businesscode.bcdui.subjectsettings.oauth2.OAuthAuthenticatingFilter
All Implemented Interfaces:
jakarta.servlet.Filter, org.apache.shiro.lang.util.Nameable, org.apache.shiro.web.filter.PathConfigProcessor

public class OAuthAuthenticatingFilter extends org.apache.shiro.web.filter.authc.AuthenticatingFilter
The flow here is (start = not authenticated request)

  1. Shiro asks AuthenticatingFilter.isAccessAllowed(ServletRequest, ServletResponse, Object), which is false if subject is not authenticated
  2. onAccessDenied(ServletRequest, ServletResponse) is called in unauthenticated case, here we detect if this a pending login-attempt (round-trip back from AD including auth-code token) or we save current request and initiate a redirect to oAuth authorization server and set redirect_url to link back to us
  3. OAuth server responses with "code" http parameter, as so isLoginRequest(ServletRequest, ServletResponse) returns true here, as such onAccessDenied(ServletRequest, ServletResponse) triggers AuthenticatingFilter.executeLogin(ServletRequest, ServletResponse)
  4. AuthenticatingFilter.executeLogin(ServletRequest, ServletResponse) queries createToken(ServletRequest, ServletResponse) to create a token (which here is basically the auth-code we got from AD), this token is passed to Subject.login(AuthenticationToken)
  5. Shiro kicks in and asks each and every available realm to process the authentication token delegated in previous step, our OAuthRealm connects to AD, queries for user-property we need internally (user-id) and returns as authenticated principal. No authorization is done on this level, just authentication, as such our oauth2 realm is authenticating only, and not authorizing
  6. whenever permission are checked, Shiro scans next realms to authorize, here our JdbcRealm loads properties from database according to principal (user-id)
  7. the onLoginSuccess(AuthenticationToken, Subject, ServletRequest, ServletResponse) is overridden as to delegate to AuthenticationFilter.issueSuccessRedirect(ServletRequest, ServletResponse) in order to redirect user to originally accessed url which was saved in step 2

      all final methods on these class define the flow and must not be changed.
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    protected class 
    Context of currently ongoing oAuth authentication flows (from selecting authenticate with oauth until success or failure) Since strict cookies are not send on redirects and flex not on posts, we cannot use Shiro's session level way of keeping this but use ehcache instead
    static enum 
     
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    protected String
     
    protected String
     
    protected String
     
    protected String
     
     
    protected String
     
    protected final SecureRandom
     
    protected String
     
    protected static final String
     

    Fields inherited from class org.apache.shiro.web.filter.authc.AuthenticatingFilter

    PERMISSIVE

    Fields inherited from class org.apache.shiro.web.filter.authc.AuthenticationFilter

    DEFAULT_SUCCESS_URL

    Fields inherited from class org.apache.shiro.web.filter.AccessControlFilter

    DEFAULT_LOGIN_URL, GET_METHOD, POST_METHOD

    Fields inherited from class org.apache.shiro.web.filter.PathMatchingFilter

    appliedPaths, pathMatcher

    Fields inherited from class org.apache.shiro.web.servlet.OncePerRequestFilter

    ALREADY_FILTERED_SUFFIX

    Fields inherited from class org.apache.shiro.web.servlet.AbstractFilter

    filterConfig
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    protected String
     
    protected org.apache.shiro.authc.AuthenticationToken
    createToken(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    AuthenticatingFilter.createToken(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse)
     
     
     
    protected String
     
    getRedirectUri(jakarta.servlet.http.HttpServletRequest request)
    Unless configured in shiro.ini, we use the current requests base url + /oauth.
     
     
    protected final boolean
    isEnabled(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    supports .enable flag and also handles a round-trip from authorization server; in order to provide extend with your logic please override isEnabledByProvider(ServletRequest, ServletResponse)
    protected Boolean
    isEnabledByProvider(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    current implementation checks if parameter URL_PARAMETER_NAME equals to getOptionalProviderId().
    protected boolean
    isLoginRequest(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    according to redirect_url set previously in redirectToLogin(ServletRequest, ServletResponse)
    protected boolean
    onAccessDenied(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    1. handles internal Shiro flow.
    protected boolean
    onLoginFailure(org.apache.shiro.authc.AuthenticationToken token, org.apache.shiro.authc.AuthenticationException e, jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    Handles the failure scenario for a login attempt.
    protected boolean
    onLoginSuccess(org.apache.shiro.authc.AuthenticationToken token, org.apache.shiro.subject.Subject subject, jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    User authenticated successfully against oAuth and is redirected to our pup-up, which then informs its opener, usually login.html, to redirect to the target URL originally addressed
    protected void
    redirectToLogin(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
    2. creates OAuthAuthenticatingFilter.RequestContext and sends http/302 with redirection to authority which will take over the authentication
    void
     
    void
    setClientId(String clientId)
     
    void
    setLoginUrl(String loginUrl)
     
    void
    setOptionalProviderId(String optionalProviderId)
     
    void
    setRedirectUri(String redirectUri)
    Optionally hard-wire redirectUri in shiro.ini If not set it is derived from the servlet context (http(s)://myserver.com/ctsPath/oauth)
    void
    setResponseMode(String responseMode)
     
    void
     
    void
    setSuccessUrl(String successUrl)
     

    Methods inherited from class org.apache.shiro.web.filter.authc.AuthenticatingFilter

    cleanup, createToken, createToken, executeLogin, getHost, isAccessAllowed, isPermissive, isRememberMe

    Methods inherited from class org.apache.shiro.web.filter.authc.AuthenticationFilter

    issueSuccessRedirect

    Methods inherited from class org.apache.shiro.web.filter.AccessControlFilter

    getLoginUrl, getSubject, onAccessDenied, onPreHandle, saveRequest, saveRequestAndRedirectToLogin

    Methods inherited from class org.apache.shiro.web.filter.PathMatchingFilter

    getPathWithinApplication, isEnabled, pathsMatch, pathsMatch, preHandle, processPathConfig

    Methods inherited from class org.apache.shiro.web.servlet.AdviceFilter

    afterCompletion, doFilterInternal, executeChain, postHandle

    Methods inherited from class org.apache.shiro.web.servlet.OncePerRequestFilter

    doFilter, getAlreadyFilteredAttributeName, isEnabled, isFilterOncePerRequest, setEnabled, setFilterOncePerRequest, shouldNotFilter

    Methods inherited from class org.apache.shiro.web.servlet.NameableFilter

    getName, setName, toStringBuilder

    Methods inherited from class org.apache.shiro.web.servlet.AbstractFilter

    destroy, getFilterConfig, getInitParam, init, onFilterConfigSet, setFilterConfig

    Methods inherited from class org.apache.shiro.web.servlet.ServletContextSupport

    getContextAttribute, getContextInitParam, getServletContext, removeContextAttribute, setContextAttribute, setServletContext, toString

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
  • Field Details

  • Constructor Details

    • OAuthAuthenticatingFilter

      public OAuthAuthenticatingFilter()
  • Method Details

    • getProviderInstanceId

      protected String getProviderInstanceId()
      Returns:
      the id of this instance
    • setSuccessUrl

      public void setSuccessUrl(String successUrl)
      Overrides:
      setSuccessUrl in class org.apache.shiro.web.filter.authc.AuthenticationFilter
    • getSuccessUrl

      public String getSuccessUrl()
      Overrides:
      getSuccessUrl in class org.apache.shiro.web.filter.authc.AuthenticationFilter
    • setResponseMode

      public void setResponseMode(String responseMode)
    • getClientId

      public String getClientId()
    • getAuthorizeEndpoint

      public String getAuthorizeEndpoint()
    • setScope

      public void setScope(String scope)
    • getScope

      public String getScope()
    • setRedirectUri

      public void setRedirectUri(String redirectUri)
      Optionally hard-wire redirectUri in shiro.ini If not set it is derived from the servlet context (http(s)://myserver.com/ctsPath/oauth)
      Parameters:
      redirectUri -
    • getRedirectUri

      public String getRedirectUri(jakarta.servlet.http.HttpServletRequest request)
      Unless configured in shiro.ini, we use the current requests base url + /oauth. Make sure, all values that can show up here are configured at the oAuth authorization server
    • setAuthorizeEndpoint

      public void setAuthorizeEndpoint(String authorityUrl)
    • setClientId

      public void setClientId(String clientId)
    • getOptionalProviderId

      public String getOptionalProviderId()
    • setOptionalProviderId

      public void setOptionalProviderId(String optionalProviderId)
    • isEnabled

      protected final boolean isEnabled(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) throws jakarta.servlet.ServletException, IOException
      supports .enable flag and also handles a round-trip from authorization server; in order to provide extend with your logic please override isEnabledByProvider(ServletRequest, ServletResponse)
      Overrides:
      isEnabled in class org.apache.shiro.web.servlet.OncePerRequestFilter
      Throws:
      jakarta.servlet.ServletException
      IOException
    • isEnabledByProvider

      protected Boolean isEnabledByProvider(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
      current implementation checks if parameter URL_PARAMETER_NAME equals to getOptionalProviderId(). You can override this method to provide different recognition, i.e. if specific HTTP header is set (i.e. by proxy)
      Parameters:
      request -
      response -
      Returns:
      true to enable processing, false to disable processing or null to delegate decision further
    • setLoginUrl

      public void setLoginUrl(String loginUrl)
      Overrides:
      setLoginUrl in class org.apache.shiro.web.filter.AccessControlFilter
    • redirectToLogin

      protected void redirectToLogin(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) throws IOException
      2. creates OAuthAuthenticatingFilter.RequestContext and sends http/302 with redirection to authority which will take over the authentication
      Overrides:
      redirectToLogin in class org.apache.shiro.web.filter.AccessControlFilter
      Parameters:
      request -
      response -
      Throws:
      IOException - in case the redirect fails
    • createToken

      protected org.apache.shiro.authc.AuthenticationToken createToken(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) throws Exception
      AuthenticatingFilter.createToken(jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse)
      Specified by:
      createToken in class org.apache.shiro.web.filter.authc.AuthenticatingFilter
      Returns:
      authentication token which is used by AuthenticatingFilter.executeLogin(ServletRequest, ServletResponse) method
      Throws:
      Exception
    • onLoginSuccess

      protected boolean onLoginSuccess(org.apache.shiro.authc.AuthenticationToken token, org.apache.shiro.subject.Subject subject, jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) throws Exception
      User authenticated successfully against oAuth and is redirected to our pup-up, which then informs its opener, usually login.html, to redirect to the target URL originally addressed
      Overrides:
      onLoginSuccess in class org.apache.shiro.web.filter.authc.AuthenticatingFilter
      Throws:
      Exception
    • onLoginFailure

      protected boolean onLoginFailure(org.apache.shiro.authc.AuthenticationToken token, org.apache.shiro.authc.AuthenticationException e, jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
      Handles the failure scenario for a login attempt. IWe provides a response indicating the login failure to the user.
      Overrides:
      onLoginFailure in class org.apache.shiro.web.filter.authc.AuthenticatingFilter
      Parameters:
      token - the authentication token used during the login attempt
      e - the authentication exception that caused the login failure
      request - the servlet request containing details of the login attempt
      response - the servlet response object to send feedback to the client
      Returns:
      always returns false to indicate the login attempt has failed
    • isLoginRequest

      protected boolean isLoginRequest(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response)
      according to redirect_url set previously in redirectToLogin(ServletRequest, ServletResponse)
      Overrides:
      isLoginRequest in class org.apache.shiro.web.filter.AccessControlFilter
      Parameters:
      request -
      response -
      Returns:
      true if this is a login request
    • onAccessDenied

      protected boolean onAccessDenied(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) throws Exception
      1. handles internal Shiro flow. It the request is an incoming request redirected from authorization-server, perform AuthenticatingFilter.executeLogin(ServletRequest, ServletResponse), otherwise redirectToLogin(ServletRequest, ServletResponse)
      Specified by:
      onAccessDenied in class org.apache.shiro.web.filter.AccessControlFilter
      Throws:
      Exception
    • createRandomString

      protected String createRandomString()
      Returns:
      random code, which can be used as code_verifier, base64url encoded