In RegServlet class, I have a doGet() method that overrides the doStuff() method. doStuff() method takes the user input from an HTML registration form, then connects to the DB, then stores the user input into the DB.
Here is the doStuff() method in my RegServlet class:
public void doStuff(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, InstantiationException, IllegalAccessException, SQLException {
String userName = request.getParameter("userName");
...
String email = request.getParameter("email");
if(!userName.isEmpty()&&!passWord.isEmpty()) {
request.setAttribute("userName", userName);
...
request.setAttribute("email", email);
//connect to DB
toDB.createConnection();
//insert information to DB
toDB.insertNewUser(userName, passWord, lastName, firstName, age, sex, email);
RequestDispatcher view = request.getRequestDispatcher("login.jsp");
view.forward(request, response);
} else {
RequestDispatcher view = request.getRequestDispatcher("index.jsp");
view.forward(request, response);
}
If the register button is clicked after everything has been entered correctly, it leads me to a login.jsp page. I am now trying to code the log-in mechanism in order for a user (who possesses username & password stored in the DB) to log in and search and add/drop courses.
I am having a hard time because I am not sure how I should go about this.
How can I isolate user registration and authentication? Should I make another class for session management or just another method in this RegServlet class?
Implement your own HTTPServletFilter that check if a user is authenticated:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
if ("a user is authenticated") {
filterChain.doFilter(req, res);
} else {
// authenticate a user
}
}
The link show the basic of HTTPServletFilter:
http://www.oracle.com/technetwork/java/filters-137243.html#70176
Related
I have a page to access with form post request (webview page for mobile apps). My application can't have a login form but I need to secure it. Mobile applications will call this webview page with authentication parameters such as (email/password). I need to call third-party api with given authentication parameters and decide it was authenticated or not. Which approach should I use for my scenarios ?
If it possible to pass authentication parameters in the Authorization header, you can enable http basic authentication in your application:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
Otherwise, you can implement your own security filter to create a UsernamePasswordAuthenticationToken (or any other class implementing Authentication) instance from your specific authentication parameters and pass to AuthenticationManager; but in the case of another class, you need to make the authentication provider below support it by overriding the public boolean supports(Class<?> authentication) method.
Then implement a custom AuthenticationProvider that will delegate authentication to the third-party API, e.g.:
public class RestAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private static final String AUTH_URL = "http://third-party-service/authentication/basic";
private RestTemplate restTemplate;
public RestAuthenticationProvider() {
this.restTemplate = new RestTemplate();
}
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
this.logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
if (!authentication.getCredentials().toString().equals(userDetails.getPassword())) {
this.logger.debug("Authentication failed: invalid credentials");
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
#Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
String password = authentication.getCredentials().toString();
try {
ResponseEntity<String> authenticationResponse = authenticate(username, password);
if (authenticationResponse.getStatusCode().value() == 401) {
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
return createUser(authenticationResponse.getBody());
} catch (BadCredentialsException ex) {
throw ex;
} catch (Exception ex) {
throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
}
}
private ResponseEntity<String> authenticate(String username, String password) {
HttpEntity entity = new HttpEntity(createHeaders(username, password));
return restTemplate.exchange(AUTH_URL, HttpMethod.GET, entity, String.class);
}
private HttpHeaders createHeaders(String username, String password) {
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
String authorization = username + ":" + password;
String basic = Base64.getEncoder().encodeToString(authorization.getBytes());
headers.set("Authorization", "Basic " + basic);
return headers;
}
private UserDetails createUser(String json) {
return null; // TODO: Implement
}
}
And finally, make Spring Security to use your provider:
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(new RestAuthenticationProvider())
.eraseCredentials(false);
}
I need to call third-party api with given authentication parameters
and decide it was authenticated or not
Assuming you need to use username / password to send to 3rd party, when you first login into the app, you can create a long lived token in back-end and sent it to the app to store in secure store. Later when you want to load the protected webview, send this token along with the request (in header or body via javascript) and in the server side pick the user / password corresponding to the token and authenticate with 3rd party.
This way you will never need to store password on client side and you can manually make the token at backend inactive too. If you like to go standard way, then you may take a look at Password Grant of OAuth 2 / OpenID Connect / . With the correct infrastructure in place you can get access tokens during login process and use that for your protected page. Spring Security has support for this flow - you can take a look here.
I hope you guys will be able to help me understand the case in servlet method doGet.
for example, we have a User class with name and the last name, of course, getters and setters are set. Additional pieces of information are in comments in the code. The question is, what is the purpose of SetAttribute in this case? Should I use it? I see no difference when its on and off. Thank you in advance for your prompt response.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//here I initiate servlet to create a session yes?
HttpSession session = request.getSession(true);
// here im getting atribiute which is goinna be null now:
User user = (User) session.getAttribute("user");
//now in case of null i want to create object which can have null atributes like name and lastname:
if(user == null) {
user = createUser(request);
//here is my problem, i dont know what is it for? I already get atrributes, why would i want to set object again? to what?
session.setAttribute("user", user);
}
returnInfo(response,user);
}
protected User createUser(HttpServletRequest request) {
User user = new User();
String name = request.getParameter("name");
String lastname = request.getParameter("lastname");
user.setName(name);
user.setSurname(lastname);
return user;
}
protected void returnInfo(HttpServletResponse response,User user) throws IOException {
PrintWriter write = response.getWriter();
write.println("<html>");
write.println("<body>");
write.println("<div>");
if(user.getName() == null && user.getSurname() == null) {
write.println("no person was added");
}
else{
write.println("person is" + " " + user.getName() + " " + user.getSurname());
}
write.println("</div>");
write.println("</body>");
write.println("</html>");
}
You have just created a new user. It must be added to the session otherwise your user attribute will always be null.
I am having trouble getting a response from the Twitter API. I am using scribe 1.3.5 here. When TwitterLoginServlet is called from one page it successfully redirects me to twitter and allows me to login. However, on the callback, TwitterCallbackServlet receives the following information in the oAuthResponse.
code - 401
message - Unauthorized
body - Failed to validate oauth signature and token
I am new to using both servlets and oauth so it is completely possible I am making some silly mistake in the following code. I believe this is all that is needed to find a solution to the problem but if you need additional information I will be checking this post vigilantly.
Thanks!
public class TwitterServlet extends HttpServlet {
private static final String SESSION_NAME_REQUEST_TOKN = "twitter.requestToken";
protected Token getRequestToken(HttpServletRequest req) {
HttpSession session = req.getSession();
try {
return (Token) session.getAttribute(SESSION_NAME_REQUEST_TOKN);
}
finally {
session.removeAttribute(SESSION_NAME_REQUEST_TOKN);
}
}
protected void setRequestToken(HttpServletRequest req, Token token) {
HttpSession session = req.getSession();
session.setAttribute(SESSION_NAME_REQUEST_TOKN, token);
}
protected OAuthRequest createRequest() {
OAuthRequest request = new OAuthRequest(Verb.GET, "https://api.twitter.com/oauth/request_token");
return request;
}
}
public class TwitterLoginServlet extends TwitterServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String callback = "http://" + request.getServerName() + ":" + request.getServerPort() + "/******/TwitterCallbackServlet";
OAuthService service = new ServiceBuilder().provider(TwitterApi.SSL.class)
.apiKey("******")
.apiSecret("******")
.callback(callback)
.build();
Token requestToken = service.getRequestToken();
setRequestToken(request, requestToken);
response.sendRedirect(service.getAuthorizationUrl(requestToken));
return;
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
public class TwitterCallbackServlet extends TwitterServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
OAuthService service = new ServiceBuilder().provider(TwitterApi.SSL.class)
.apiKey("******")
.apiSecret("******")
.build();
Token requestToken = getRequestToken(request);
// TODO: Check if the requestToken matches the token of this request.
String verifier = request.getParameter(OAuthConstants.VERIFIER);
Token accessToken = service.getAccessToken(requestToken, new Verifier(verifier));
OAuthRequest oAuthRequest = createRequest();
service.signRequest(accessToken, oAuthRequest);
Response oAuthResponse = oAuthRequest.send();
String body = oAuthResponse.getBody();
response.sendRedirect("/******/accountSettings.xhtml");
}
Why are you hitting the requestToken endpoint again after getting the access token? Try accessing a different resource, for example:
"https://api.twitter.com/1.1/account/verify_credentials.json";
Note that you can run the TwitterExample just to check that stuff is working fine.
I added the following line in alfresco log 4j file.
log4j.logger.org.alfresco.util.log.NDC=debug
log4j.appender.File.layout.ConversionPattern=%d{ABSOLUTE} %x %-5p [%c] %m%n
But still the log file is not logging the user login access.
How to make alfresco share to log the user login details.
Share does not support NDC logging of the username out of the box - only the repository does. However, it can easily be implemented with a filter:
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String userId = AuthenticationUtil.getUserId((HttpServletRequest) request);
NDC.remove();
if (userId != null) {
NDC.push("User:" + userId);
}
chain.doFilter(request, response);
}
The opposite of: How to manually log out a user with spring security?
In my app I have register new user screen, which posts to a controller which creates a new user within db (and does a few obvious checks).I then want this new user to be automatically logged in ... I kind of want somethign like this :
SecurityContextHolder.getContext().setPrincipal(MyNewUser);
Edit
Well I have almost implemented based on the answer to How to programmatically log user in with Spring Security 3.1
Authentication auth = new UsernamePasswordAuthenticationToken(MyNewUser, null);
SecurityContextHolder.getContext().setPrincipal(MyNewUser);
However, when deployed the jsp can not access my MyNewUser.getWhateverMethods() whereas it does when normal login procedure followed. the code that works nomrally, but throws an error when logged in like above is below :
<sec:authentication property="principal.firstname" />
In my controller i have this, which logs user in as normal :
Authentication auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
Where user is my custom user object(implementing UserDetails) that is newly created. The getAuthorities() method does this (just because all my users have the same role):
public Collection<GrantedAuthority> getAuthorities() {
//make everyone ROLE_USER
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
GrantedAuthority grantedAuthority = new GrantedAuthority() {
//anonymous inner type
public String getAuthority() {
return "ROLE_USER";
}
};
grantedAuthorities.add(grantedAuthority);
return grantedAuthorities;
}
You can also inject your spring security configured UserDetailsManager to your controller and use that to get the UserDetails which holds the principal and authorities to avoid duplicate code:
// inject
#Autowired
private UserDetailsManager manager;
// use in your method
UserDetails userDetails = manager.loadUserByUsername (token.getUsername ());
Authentication auth = new UsernamePasswordAuthenticationToken (userDetails.getUsername (),userDetails.getPassword (),userDetails.getAuthorities ());
SecurityContextHolder.getContext().setAuthentication(auth);
From the spring security source AbstractAuthenticationProcessingFilter:
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
Authentication authResult) throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
}
// you need this
SecurityContextHolder.getContext().setAuthentication(authResult);
rememberMeServices.loginSuccess(request, response, authResult);
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request, response, authResult);
}
Note however that the SecurityContextHolder is usually cleared upon completion of the filter chain.
For anyone trying to do this with Reactive Spring Security, this is what I did and it seemed to work.
private Mono<Authentication> authenticateUser(ServerWebExchange exchange, UserDetails userDetails,String rawPassword)
{
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails.getUsername(),rawPassword);
return reactiveAuthenticationManager.authenticate(token).filter(auth -> auth.isAuthenticated()).flatMap(auth ->
{
SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(auth);
return securityContextRepository.save(exchange,securityContext).then(Mono.just(auth));
});
}