Spring security custom successHandler not called - authentication

I create my custom authentication filter, provider and successHandler and they are work except successHandler. I set uo authentication-success-handler-ref but it looks like not called. In logs is used default SavedRequestAwareAuthenticationSuccessHandler. I use spring security 4.2.2 and mitreid openid coennect project. I saw many examples how to set up your custom successHandler but they wasn't work.
My filter
#Component("custAuthRequestFilter")
public class custAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_SESSION_KEY = "custSession";
private String sessionParameter = SPRING_SECURITY_FORM_SESSION_KEY;
private static final Logger LOG = LoggerFactory.getLogger(CustAuthenticationFilter.class);
protected CustAuthenticationFilter() {
super(new AntPathRequestMatcher("/custlogin", "POST"));
}
#Override
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
if (isCustSession(request)) {
final CustAuthenticationToken authRequest = getAuthRequest(request);
return getAuthenticationManager().authenticate(authRequest);
} else {
throw new AuthenticationServiceException("Authentication is not possible, CustSession is missing");
}
}
#Autowired
#Qualifier("custAuthenticationManager")
#Override
public void setAuthenticationManager(final AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
private CustAuthenticationToken getAuthRequest(final HttpServletRequest request) {
final String session = obtainSession(request);
return new CustAuthenticationToken(session);
}
private boolean isCustSession(final HttpServletRequest request) {
return !StringUtils.isEmpty(request.getParameter(sessionParameter));
}
private String obtainSession(final HttpServletRequest request) {
return request.getParameter(sessionParameter);
}
}
My provider
#Component("custAuthenticationProvider")
public class CustAuthenticationProvider
implements AuthenticationProvider {
private final static Logger LOG = LoggerFactory.getLogger(CustAuthenticationProvider.class);
#Autowired
private CoreClient coreClient;
#Autowired
private InMemoryRepository db;
#Override
public Authentication authenticate(final Authentication auth)
throws AuthenticationException {
LOG.debug("Get user info by session from core service");
try {
final List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
final UserDataMap result = coreClient.getUserDataMap(custToken.getPrincipal().toString());
return new CustAuthenticationToken(custToken.getPrincipal().toString(), authorities);
} catch(final Exception exc) {
throw new InternalAuthenticationServiceException("Internal error", exc);
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(CustAuthenticationToken.class);
}
}
My custom successHandler
#Component("custSuccessHandler")
public class CustAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private static final Logger LOG = LoggerFactory.getLogger(CustAuthenticationSuccessHandler.class);
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
LOG.debug(">>>>>>>>>>>>>>>>>>>>> success handler");
HttpSession session = request.getSession();
super.onAuthenticationSuccess(request, response, authentication);
}
}
user-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="io.oidcconnector.auth" />
<security:authentication-manager id="custAuthenticationManager">
<security:authentication-provider ref="custAuthenticationProvider"/>
</security:authentication-manager>
<security:authentication-manager id="authenticationManager">
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"/>
</security:authentication-provider>
</security:authentication-manager>
<mvc:view-controller path="/login" view-name="login" />
<security:http authentication-manager-ref="authenticationManager" >
<security:intercept-url pattern="/authorize" access="hasRole('ROLE_USER')" />
<security:intercept-url pattern="/**" access="permitAll" />
<security:form-login login-page="/custlogin" authentication-failure-url="/custlogin?error=failure" authentication-success-handler-ref="custSuccessHandler" />
<security:form-login login-page="/login" authentication-failure-url="/login?error=failure" authentication-success-handler-ref="authenticationTimeStamper" />
<security:custom-filter ref="authRequestFilter" after="SECURITY_CONTEXT_FILTER" />
<security:custom-filter ref="custAuthRequestFilter" before="FORM_LOGIN_FILTER" />
<security:logout logout-url="/logout" />
<security:anonymous />
<security:expression-handler ref="oauthWebExpressionHandler" />
<security:headers>
<security:frame-options policy="DENY" />
</security:headers>
<security:csrf />
</security:http>
<mvc:view-controller path="/custlogin" view-name="custlogin" />
logs
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher -
Checking match of request : '/custlogin'; against '/custlogin'
DEBUG: io.oidcconnector.auth.CustAuthenticationFilter - Request is to process authentication
DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using io.oidcconnector.auth.CUstAuthenticationProvider
DEBUG: io.oidcconnector.auth.CustAuthenticationProvider - Get user info by session from core service
DEBUG: io.oidcconnector.auth.CUstAuthenticationFilter - Authentication success. Updating SecurityContextHolder to contain: io.oidcconnector.auth.CustAuthenticationToken#441c7a52: Principal: abc; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER
DEBUG: org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler - Using default Url: /
DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/oidc-connector/'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext 'org.springframework.security.core.context.SecurityContextImpl#441c7a52: Authentication: io.oidcconnector.auth.CUstAuthenticationToken#441c7a52: Principal: abc; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade#328f5fdf
I have no idea why this not working.

Related

Unable to authenticate with UsernameAndPasswordToken and set Cookie with Spring Security

I am building Spring Boot/ReactJS app and i have following issue in authenticating the user and generating JSSESSIONID.
My SecurityConfig class looks like this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder());
}
#Override
#Bean(BeanIds.AUTHENTICATION_MANAGER)
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.logout().deleteCookies("JSESSIONID")
.and()
.rememberMe().key("uniqueAndSecret").tokenValiditySeconds(86400)
.and()
.csrf().disable();
}
#Bean
BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder();}
}
And my LoginController:
#RestController
#RequestMapping(path="/",produces = "application/json")
#CrossOrigin(origins="*")
public class LoginController {
private final AuthenticationManager authenticationManager;
public LoginController(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#PostMapping("/login")
#ResponseStatus(HttpStatus.OK)
public void login(HttpServletRequest req, #RequestBody LoginRequest loginRequest) {
UsernamePasswordAuthenticationToken authReq
= new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
Authentication auth = authenticationManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
HttpSession session = req.getSession(true);
session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
}
}
And when i call request, i have a BadCredentials exception thrown when calling authenticationManager.authenticate(authReq)
because the authReq's content log is
org.springframework.security.authentication.UsernamePasswordAuthenticationToken#6582813: Principal: pavel; Credentials: [PROTECTED]; Authenticated: false; Details: null; Not granted any authorities
Am i missing some part of configuration here?

Browser not prompting for credentials using basic authentication

My goal is to provide authentication to a single resource on the server, for this I am using custom filter. I am not using #NameBinding because of constraint of using JAVA 1.6.Using Response.header(HttpHeaders.WWW_AUTHENTICATE,"Basic") is not prompting for credentials.
Using ContainerRequestFilter is not helping my cause as it will put filter on every resource of server.
Filter
#Provider
public class AuthenticationFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
System.out.println("Entered authentication filter");
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.AUTHORIZATION,"Basic")
.entity("Credentials are required to access this resource.")
.build());
// chain.doFilter(req, resp);
}
#Override
public void init(FilterConfig arg0) throws ServletException {}
#Override
public void destroy() {}
}
web.xml mapping
<filter>
<filter-name>AuthenticationFilter</filter-name>
<filter-class>Utils.LDAPAuthentication.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/download</url-pattern>
</filter-mapping>
The response I am getting on hitting the webservice is
So as suggested by Paul , I used HttpServletResponse.
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if(request.getHeader("Authorization")==null){
response.setHeader(HttpHeaders.WWW_AUTHENTICATE,"Basic");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
else{
String credentials = request.getHeader("Authorization");
}

Error in my simple struts application

Error: inconvertible types
my loginAction file's code:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception
{
LoginForm loginForm = (LoginForm) form;
if (loginForm.getUserName().equals(loginForm.getPassword()))
{
return mapping.findForward(SUCCESS);
}
else
{
return mapping.findForward(FAILURE);
}
}
my struts-config file's code:
<action-mappings>
<action input="/login.jsp" name="LoginForm" path="/Login" scope="session" type="com.strutsmyaction.LoginAction">
<forward name="success" path="/success.jsp" />
<forward name="failure" path="/failure.jsp" />
</action>
</action-mappings>
my loginform file's code
public class LoginForm
{ String userName; String password;
public String getUserName() {
System.out.println("Inside getter "+userName);
return userName;
}
public void setUserName(String userName) {
System.out.println("Inside setter "+userName);
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
I think This will work ..
if (loginForm.getUserName().equals(loginForm.getPassword()))
{
return mapping.findForward("success");
}
else
{
return mapping.findForward("failure");
}

Apache CXF - Set HTTP header

I have to set some http header fields in a Apache CXF client:
I tried it via Interceptor:
public class HttpHeaderInterceptor extends AbstractPhaseInterceptor<Message> {
private String userId;
private String xAuthorizeRoles;
private String host;
public HttpHeaderInterceptor() {
super(Phase.POST_PROTOCOL);
}
#Override
public void handleMessage(Message message) throws Fault {
Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS);
try {
System.out.println("HttpHeaderInterceptor Host: " + host + " UserId: " + userId + " X-AUTHORIZE-roles: " + xAuthorizeRoles);
headers.put("Host", Collections.singletonList(host));
headers.put("UserId", Collections.singletonList(userId));
headers.put("X-AUTHORIZE-roles", Collections.singletonList(xAuthorizeRoles));
} catch (Exception ce) {
throw new Fault(ce);
}
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setxAuthorizeRoles(String xAuthorizeRoles) {
this.xAuthorizeRoles = xAuthorizeRoles;
}
public void setHost(String host) {
this.host = host;
}
}
in my dynamic client class the methode:
public void setHttHeaderInterceptor(String userId, String xAuthorizeRoles){
Client cxfClient = ClientProxy.getClient(this.abgWebServicePort);
HttpHeaderInterceptor httpHeaderInterceptor = new HttpHeaderInterceptor();
httpHeaderInterceptor.setHost("example.org");
httpHeaderInterceptor.setUserId(userId);
httpHeaderInterceptor.setxAuthorizeRoles(xAuthorizeRoles);
cxfClient.getOutInterceptors().add(httpHeaderInterceptor);
}
is called before I invoke the remote service:
For each call the userId and the xAuthorizeRoles should vary but when I inspect by calls via tcpdump all calls have the same values in the header fields.
Any ideas?
I Have solved my problem:
adding the interceptor via xml configuration:
<jaxws:client id="clientBean" serviceClass="org.example.service.ServicePortType"
address="example.org/src/service/ServicePort">
<jaxws:outInterceptors>
<bean class="org.example.interceptor.HttpHeaderInterceptor"/>
</jaxws:outInterceptors>
<jaxws:properties>
<entry key="mtom-enabled" value="true"/>
</jaxws:properties>
</jaxws:client>
in the client class I altered setHttpHeaderInterceptor to
public void setHttpHeaderInterceptor(String userId, String xAuthorizeRoles){
Client cxfClient = ClientProxy.getClient(this.servicePort);
cxfClient.getRequestContext().put("HTTP_HEADER_HOST", "example.org");
cxfClient.getRequestContext().put("HTTP_HEADER_USER_ID", userId);
cxfClient.getRequestContext().put("HTTP_HEADER_X_AUTHORIZE-ROLES", xAuthorizeRoles);
}
the interceptor class
#Override
public void handleMessage(Message message) throws Fault {
Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS);
try {
headers.put("Host", Collections.singletonList(message.get("HTTP_HEADER_HOST")));
headers.put("KD_NR", Collections.singletonList(message.get("HTTP_HEADER_KD_NR")));
headers.put("X-AUTHORIZE-roles", Collections.singletonList(message.get("HTTP_HEADER_X_AUTHORIZE-ROLES")));
} catch (Exception ce) {
throw new Fault(ce);
}
}
and now it work's.
With this approach I can set HTTP-Header fields at runtime.
You should have used :Phase.POST_LOGICAL instead of Phase.POST. This worked for me
Here is a code snippet to copy a custom HTTP header (from the request) on the response in a single CXF out interceptor.
public void handleMessage(SoapMessage message) throws Fault {
// Get request HTTP headers
Map<String, List<String>> inHeaders = (Map<String, List<String>>) message.getExchange().getInMessage().get(Message.PROTOCOL_HEADERS);
// Get response HTTP headers
Map<String, List<String>> outHeaders = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS);
if (outHeaders == null) {
outHeaders = new HashMap<>();
message.put(Message.PROTOCOL_HEADERS, outHeaders);
}
// Copy Custom HTTP header on the response
outHeaders.put("myCustomHTTPHeader", inHeaders.get("myCustomHTTPHeader"));
}
If required to set standard HTTP header then it can be done using http conduit also.
<http-conf:conduit
name="*.http-conduit">
<http-conf:client AllowChunking="false" AcceptEncoding="gzip,deflate" Connection="Keep-Alive"
Host="myhost.com"/>
</http-conf:conduit>

Can't get Form Validation working

I was learning Struts 1.1 and trying to do some form validation with my code.
But the errors that I had described in the MessageResources.properties file do not get displayed on the JSP. I tried a lot of options but couldn't get it off the ground. I have attached some of the code.
MessageResources.properties
error.name.required = Please mention your name.
error.email.incorrect = You E-Mail ID is Incorrect.
error.phone.numericError = Phone number should consist only of digits.
error.phone.lengthIncorrect = Phone number should be only of 10 digits.
struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="detailsForm" type="com.example.form.DetailsForm"/>
</form-beans>
<action-mappings>
<action input="/detailsEntry.jsp" name="detailsForm" path="/DetailsForm" type="com.example.action.DetailsAction" validate="true">
<forward name="success" path="/displayDetails.jsp"/>
<forward name="failure" path="/failure.jsp"/>
</action>
</action-mappings>
</struts-config>
Form Class:
package com.example.form;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
public class DetailsForm extends ActionForm {
private String name;
private String email;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
#Override
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.name = null;
this.email = null;
this.phone = null;
}
#Override
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors actionErrors = new ActionErrors();
if (this.name.equals(null) || this.name.length() == 0) {
actionErrors.add("name", new ActionError("error.name.required"));
}
return actionErrors;
}
private boolean isNumeric(String phoneNumber) {
try {
Integer.parseInt(phoneNumber);
return true;
}
catch (NumberFormatException numberFormatException) {
return false;
}
}
}
The default resource filename is ApplicationResources.properties.
Using a different (or multiple) resource files requires configuration in struts-config.xml:
<message-resource parameter="MessageResources" null="false" />
Don't forget to add the following to your jsp:
<html:errors />
Your error messages will appear where ever you put this tag on on your jsp.
And if you want your error message to be displayed next to the field they relates to then use the following:
<html:errors property="custName" />
where "custName" is the name you gave the error message when you created it in your form ex:
ActionMessages errors = new ActionMessages();
errors.add("custName", new ActionMessage("custName.invalid"));
request.setAttribute(Globals.ERROR_KEY, errors);