add anonymous mode for webclient / change footer and redirects if user is anonymous / add login button if user is anonymous

This commit is contained in:
Eduard Heimbuch
2020-08-03 17:41:40 +02:00
parent b926238e03
commit 4c9e96f7e2
21 changed files with 324 additions and 151 deletions

View File

@@ -29,6 +29,8 @@ import sonia.scm.SCMContext;
public class Authentications {
private Authentications() {}
public static boolean isAuthenticatedSubjectAnonymous() {
return isSubjectAnonymous((String) SecurityUtils.getSubject().getPrincipal());
}

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.web.filter;
//~--- non-JDK imports --------------------------------------------------------
@@ -59,16 +59,21 @@ import java.util.Set;
* @since 2.0.0
*/
@Singleton
public class AuthenticationFilter extends HttpFilter
{
public class AuthenticationFilter extends HttpFilter {
/** marker for failed authentication */
/**
* marker for failed authentication
*/
private static final String ATTRIBUTE_FAILED_AUTH = "sonia.scm.auth.failed";
/** Field description */
/**
* Field description
*/
private static final String HEADER_AUTHORIZATION = "Authorization";
/** the logger for AuthenticationFilter */
/**
* the logger for AuthenticationFilter
*/
private static final Logger logger =
LoggerFactory.getLogger(AuthenticationFilter.class);
@@ -77,7 +82,7 @@ public class AuthenticationFilter extends HttpFilter
/**
* Constructs a new basic authenticaton filter.
*
* @param configuration scm-manager global configuration
* @param configuration scm-manager global configuration
* @param tokenGenerators web token generators
*/
@Inject
@@ -92,41 +97,32 @@ public class AuthenticationFilter extends HttpFilter
* Handles authentication, if a one of the {@link WebTokenGenerator} returns
* an {@link AuthenticationToken}.
*
* @param request servlet request
* @param request servlet request
* @param response servlet response
* @param chain filter chain
*
* @param chain filter chain
* @throws IOException
* @throws ServletException
*/
@Override
protected void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = createToken(request);
if (token != null)
{
if (token != null) {
logger.trace(
"found authentication token on request, start authentication");
handleAuthentication(request, response, chain, subject, token);
}
else if (subject.isAuthenticated())
{
} else if (subject.isAuthenticated()) {
logger.trace("user is already authenticated");
processChain(request, response, chain, subject);
}
else if (isAnonymousAccessEnabled() && !HttpUtil.isWUIRequest(request))
{
} else if (isAnonymousAccessEnabled()) {
logger.trace("anonymous access granted");
subject.login(new AnonymousToken());
processChain(request, response, chain, subject);
}
else
{
} else {
logger.trace("could not find user send unauthorized");
handleUnauthorized(request, response, chain);
}
@@ -136,28 +132,22 @@ public class AuthenticationFilter extends HttpFilter
* Sends status code 403 back to client, if the authentication has failed.
* In all other cases the method will send status code 403 back to client.
*
* @param request servlet request
* @param request servlet request
* @param response servlet response
* @param chain filter chain
*
* @param chain filter chain
* @throws IOException
* @throws ServletException
*
* @since 1.8
*/
protected void handleUnauthorized(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// send only forbidden, if the authentication has failed.
// see https://bitbucket.org/sdorra/scm-manager/issue/545/git-clone-with-username-in-url-does-not
if (Boolean.TRUE.equals(request.getAttribute(ATTRIBUTE_FAILED_AUTH)))
{
if (Boolean.TRUE.equals(request.getAttribute(ATTRIBUTE_FAILED_AUTH))) {
sendFailedAuthenticationError(request, response);
}
else
{
} else {
sendUnauthorizedError(request, response);
}
}
@@ -165,16 +155,13 @@ public class AuthenticationFilter extends HttpFilter
/**
* Sends an error for a failed authentication back to client.
*
*
* @param request http request
* @param request http request
* @param response http response
*
* @throws IOException
*/
protected void sendFailedAuthenticationError(HttpServletRequest request,
HttpServletResponse response)
throws IOException
{
HttpServletResponse response)
throws IOException {
HttpUtil.sendUnauthorized(request, response,
configuration.getRealmDescription());
}
@@ -182,16 +169,13 @@ public class AuthenticationFilter extends HttpFilter
/**
* Sends an unauthorized error back to client.
*
*
* @param request http request
* @param request http request
* @param response http response
*
* @throws IOException
*/
protected void sendUnauthorizedError(HttpServletRequest request,
HttpServletResponse response)
throws IOException
{
HttpServletResponse response)
throws IOException {
HttpUtil.sendUnauthorized(request, response,
configuration.getRealmDescription());
}
@@ -200,20 +184,15 @@ public class AuthenticationFilter extends HttpFilter
* Iterates all {@link WebTokenGenerator} and creates an
* {@link AuthenticationToken} from the given request.
*
*
* @param request http servlet request
*
* @return authentication token of {@code null}
*/
private AuthenticationToken createToken(HttpServletRequest request)
{
private AuthenticationToken createToken(HttpServletRequest request) {
AuthenticationToken token = null;
for (WebTokenGenerator generator : tokenGenerators)
{
for (WebTokenGenerator generator : tokenGenerators) {
token = generator.createToken(request);
if (token != null)
{
if (token != null) {
logger.trace("generated web token {} from generator {}",
token.getClass(), generator.getClass());
@@ -227,30 +206,24 @@ public class AuthenticationFilter extends HttpFilter
/**
* Handle authentication with the given {@link AuthenticationToken}.
*
*
* @param request http servlet request
* @param request http servlet request
* @param response http servlet response
* @param chain filter chain
* @param subject subject
* @param token authentication token
*
* @param chain filter chain
* @param subject subject
* @param token authentication token
* @throws IOException
* @throws ServletException
*/
private void handleAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Subject subject,
AuthenticationToken token)
throws IOException, ServletException
{
HttpServletResponse response, FilterChain chain, Subject subject,
AuthenticationToken token)
throws IOException, ServletException {
logger.trace("found basic authorization header, start authentication");
try
{
try {
subject.login(token);
processChain(request, response, chain, subject);
}
catch (AuthenticationException ex)
{
} catch (AuthenticationException ex) {
logger.warn("authentication failed", ex);
handleUnauthorized(request, response, chain);
}
@@ -259,33 +232,26 @@ public class AuthenticationFilter extends HttpFilter
/**
* Process the filter chain.
*
*
* @param request http servlet request
* @param request http servlet request
* @param response http servlet response
* @param chain filter chain
* @param subject subject
*
* @param chain filter chain
* @param subject subject
* @throws IOException
* @throws ServletException
*/
private void processChain(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Subject subject)
throws IOException, ServletException
{
HttpServletResponse response, FilterChain chain, Subject subject)
throws IOException, ServletException {
String username = Util.EMPTY_STRING;
if (!subject.isAuthenticated())
{
if (!subject.isAuthenticated()) {
// anonymous access
username = SCMContext.USER_ANONYMOUS;
}
else
{
} else {
Object obj = subject.getPrincipal();
if (obj != null)
{
if (obj != null) {
username = obj.toString();
}
}
@@ -299,19 +265,21 @@ public class AuthenticationFilter extends HttpFilter
/**
* Returns {@code true} if anonymous access is enabled.
*
*
* @return {@code true} if anonymous access is enabled
*/
private boolean isAnonymousAccessEnabled()
{
private boolean isAnonymousAccessEnabled() {
return (configuration != null) && configuration.getAnonymousMode() != AnonymousMode.OFF;
}
//~--- fields ---------------------------------------------------------------
/** set of web token generators */
/**
* set of web token generators
*/
private final Set<WebTokenGenerator> tokenGenerators;
/** scm main configuration */
/**
* scm main configuration
*/
protected ScmConfiguration configuration;
}