/*
* Copyright (C) 2008-2020, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package com.juick.service.security;
import com.juick.model.User;
import com.juick.service.ActivityPubService;
import com.juick.service.UserService;
import com.juick.service.security.entities.JuickUser;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
public class HTTPSignatureAuthenticationFilter extends BaseAuthenticationFilter {
private final ActivityPubService signatureManager;
private final UserService userService;
public HTTPSignatureAuthenticationFilter(
final ActivityPubService activityPubService,
final UserService userService) {
this.signatureManager = activityPubService;
this.userService = userService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
if (authenticationIsRequired()) {
Map headers = Collections.list(request.getHeaderNames())
.stream()
.collect(Collectors.toMap(String::toLowerCase, request::getHeader));
var user = signatureManager.verifyActor(request.getMethod(), request.getRequestURI(), headers);
String userUri = user.getUri().toString();
if (!user.isAnonymous() || userUri.length() > 0) {
if (userUri.length() == 0) {
User userWithPassword = userService.getUserByName(user.getName());
userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid()));
Authentication authentication = new UsernamePasswordAuthenticationToken(
new JuickUser(user), userWithPassword.getCredentials(), JuickUser.USER_AUTHORITY);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
// anonymous must have with uri
Authentication authentication = new AnonymousAuthenticationToken(userUri,
new JuickUser(user), JuickUser.ANONYMOUS_AUTHORITY);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
filterChain.doFilter(request, response);
}
}