I am trying to develop a simple BigQuery App using JSP Servlets. I am following the exampla given on https://developers.google.com/bigquery/docs/authorization
In the early stages, the doGet method was not getting invoked and so I overrided the Service method. The code looks like this
public class BigQueryWebServerAuthDemo extends AbstractAuthorizationCodeServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
System.out.println(" Start service ");
doGet(req, resp);
}
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
System.out.println(" Start doGet ");
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
System.out.println(" Start doPost ");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
System.out.println(" Begin loadbigquery() ");
Bigquery bigquery = CredentialUtils.loadbigquery();
System.out.println(" end loadbigquery() ");
Bigquery.Projects.List projectListRequest = bigquery.projects().list();
ProjectList projectList = projectListRequest.execute();
if (projectList.getProjects() != null) {
java.util.List<Projects> projects = projectList.getProjects();
writer.println("<h3>BigQuery project list:</h3>");
for (ProjectList.Projects project : projects) {
writer.printf("%s<br />", project.getProjectReference().getProjectId());
}
}
System.out.println(" End doPost ");
}
#Override
protected AuthorizationCodeFlow initializeFlow() throws ServletException, IOException {
System.out.println(" inside BigQueryWebServerAuthDemo --- initializeFlow() ");
return CredentialUtils.newFlow();
}
#Override
protected String getRedirectUri(HttpServletRequest request) throws ServletException, IOException {
System.out.println(" inside BigQueryWebServerAuthDemo --- getRedirectUri() ");
return CredentialUtils.getRedirectUri(request);
}
#Override
protected String getUserId(HttpServletRequest request) throws ServletException, IOException {
System.out.println(" inside BigQueryWebServerAuthDemo --- getUserId ");
return request.getParameter("userId");
}
}
I have a JSP page from where I am getting the parameter "userId". Now I get a
NoSuchMethodError on execute() method [projectListRequest.execute()] though Eclipse compiler doesnt show any error.
Below is my web.xml config info
<servlet>
<servlet-name>oauth2callback</servlet-name>
<servlet-class>main.BigQueryWebServerAuthCallBack</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>oauth2callback</servlet-name>
<url-pattern>/oauth2callback</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ServletBigQuery</servlet-name>
<servlet-class>main.BigQueryWebServerAuthDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletBigQuery</servlet-name>
<url-pattern>/ServletBigQuery</url-pattern>
</servlet-mapping>
I have 2 more classes CredentialUtils and BigQueryWebServerAuthCallBack as given in the tutorial mentioned above.
I am actually new to Java . I want get rid of the NoSuchMethodError error. Any help will be greatly appreciated.
Related
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");
}
I'm writing backend app based on Spring Boot without any views (templates), because client app will use it's own HTML.
I'm trying change default behavior (HTTP POST) Spring Security form-login authentication - use HTTP GET and POST. Yes, I know, it's bad for security, but it's requirement.
How I can do it?
My app:
Application
package net.company.rest;
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SecurityConfig
package net.company.rest.config;
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthSuccessHandler authSuccessHandler;
#Autowired
private AuthFailureHandler authFailureHandler;
#Autowired
private AuthEntryPoint authEntryPoint;
// configure security
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
http.exceptionHandling().authenticationEntryPoint(authEntryPoint);
http.formLogin().usernameParameter("user").passwordParameter("pass");
http.formLogin().successHandler(authSuccessHandler).failureHandler(authFailureHandler);
http.logout().permitAll();
http.cors();
http.csrf().disable();
}
// enable security
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
for (int i = 1; i <= 10; i++) {
auth.inMemoryAuthentication().withUser("user" + i).password("user" + i).roles("USER");
}
}
}
AuthEntryPoint
package net.company.rest.component;
#Component
public class AuthEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest req,
HttpServletResponse resp,
AuthenticationException ex) throws IOException, ServletException {
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
UniversalMessage msg = new UniversalMessage(1, "not authenticated");
try {
resp.getWriter().print(new ObjectMapper().writeValueAsString(msg));
} catch (JsonProcessingException e) {
resp.getWriter().print(e.toString());
}
resp.getWriter().flush();
}
}
AuthSuccessHandler
package net.company.rest.component;
#Component
public class AuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest req,
HttpServletResponse resp,
Authentication auth) throws ServletException, IOException {
resp.setStatus(HttpServletResponse.SC_OK);
UniversalMessage msg = new UniversalMessage(0, "auth success");
try {
resp.getWriter().print(new ObjectMapper().writeValueAsString(msg));
} catch (JsonProcessingException e) {
resp.getWriter().print(e.toString());
}
resp.getWriter().flush();
clearAuthenticationAttributes(req);
}
}
AuthFailureHandler
package net.company.rest.component;
#Component
public class AuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest req,
HttpServletResponse resp,
AuthenticationException ex) throws IOException, ServletException {
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
UniversalMessage msg = new UniversalMessage(1, "auth error");
try {
resp.getWriter().print(new ObjectMapper().writeValueAsString(msg));
} catch (JsonProcessingException e) {
resp.getWriter().print(e.toString());
}
resp.getWriter().flush();
}
}
The problem was that above code didn't solve problem, login by HTTP GET didn't work anyway.
There is steps for solve:
Add new class extends UsernamePasswordAuthenticationFilter
package net.company.rest.config.web;
#Slf4j
public class AuthByGetFilter extends UsernamePasswordAuthenticationFilter {
public AuthByGetFilter() {
super();
// change auth parameters
setUsernameParameter("user");
setPasswordParameter("pass");
// allow GET
setPostOnly(false);
setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "GET"));
}
#Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
SecurityContextHolder.clearContext();
log.debug("Method: {}, Request: {}, params was hidden for security", request.getMethod(), request.getRequestURL());
log.debug("Authentication request failed: {}", failed.toString());
log.debug("Updated SecurityContextHolder to contain null Authentication");
log.debug("Delegating to authentication failure handler " + getFailureHandler());
getRememberMeServices().loginFail(request, response);
getFailureHandler().onAuthenticationFailure(request, response, failed);
}
}
Use this class as filter in the above described SecurityConfig class
...
// configure security
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(authByGetFilter(), UsernamePasswordAuthenticationFilter.class); // add authByGetFilter
...
}
// allow authentication by http GET method
#Bean
public AuthByGetFilter authByGetFilter() throws Exception {
AuthByGetFilter authByGetFilter = new AuthByGetFilter();
authByGetFilter.setAuthenticationManager(authenticationManagerBean());
authByGetFilter.setAuthenticationFailureHandler(authFailureHandler);
authByGetFilter.setAuthenticationSuccessHandler(authSuccessHandler);
return authByGetFilter;
}
...
I have a REST handler servlet defined as follows (this works perfectly):
//REST handler context
ServletContextHandler restHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
restHandler.setContextPath("/");
// Jersey REST handling servlet
ServletHolder jerseyServlet = restHandler.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
// Tell Jersey which REST service class to load....
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", RestHandler.class.getCanonicalName());
I now want to add a authentication filter, which I do as:
FilterHolder authFilter = restHandler.addFilter(AuthFilter.class, "/",
EnumSet.of( DispatcherType.ASYNC,
DispatcherType.ERROR,
DispatcherType.FORWARD,
DispatcherType.INCLUDE,
DispatcherType.REQUEST));
if (authFilter == null) {
dlog.debug("Failed to load authentication filter");
};
All good so far, however, the filter does not fire on incoming REST. Calls still go through. The AuthFilter is straight from sample code:
public class AuthFilter implements javax.servlet.Filter {
private static final Logger dlog = Dlog.get();
public static final String AUTHENTICATION_HEADER = "Authorization";
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filter)
throws IOException, ServletException {
dlog.entry(request, response, filter);
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authCredentials = httpServletRequest.getHeader(AUTHENTICATION_HEADER);
AuthService authenticationService = new AuthService();
boolean authenticationStatus = authenticationService.authenticate(authCredentials);
if (authenticationStatus) {
filter.doFilter(request, response);
} else {
if (response instanceof HttpServletResponse) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
dlog.exit();
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
I use handler collection as I also have a resource handler to serve static web pages besides the REST calls.
HandlerCollection handlerList = new HandlerCollection();
handlerList.setHandlers(new Handler[] { resourceHandler,
restHandler,
new DefaultHandler(),
requestLogHandler });
What else I need to do? I have scanned through number of related posts and come up empty. Thanks in advance.
I have a simple component for my own ErrorHandler implementation:
#Component(immediate = true)
#Service
#Properties(
#Property(name = "service.ranking", intValue = 1)
)
public class MyErrorHandler implements ErrorHandler {
#Override
public void handleError(int status, String message, SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
handleError(status, request, response);
}
#Override
public void handleError(Throwable throwable, SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
handleError(505, request, response);
}
private void handleError(int status, SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
if (status != 200) {
try {
request.getRequestDispatcher("/etc/errors/" + status + ".html").forward(request, response);
} catch (ServletException e) {
throw new IllegalStateException("No error pages");
}
}
}
If I deploy the component to Sling, nothings happen until restart of whole Sling. It's not a good solution I guess.
Short explanation about using ErrorHandler instead of handling scripts (for those who would ask 'why you didn't use overloaded script)
Writing own Servlet is too complex for that easy behaviour
Scripts are less maintainable than java code (in sling).
I'm trying to accomplish a jsf2-based form login where a user can go straight to his chosen URL after being redirected to the login-page. How can this be accomplished? My current settings are as following (using glassfish 3)
Web.XML
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/login.jsf</form-error-page>
</form-login-config>
</login-config>
<security-constraint> //(omitted) all pages except login.jsf requires login </security-constraint>
Session scoped managed bean handling login
public String login(){
try{
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
request.login(username, pwd);
loggedInUser = userBean.findByLogin(username);
username = null;
pwd = null;
//context.getExternalContext().redirect((String)request.getAttribute("from"));
return "/index?faces-redirect=true";
} catch(Exception e){
logger.log(Level.FINE, "login failed: {0}", e.getMessage());
JsfUtil.addErrorMessage("Login failed");
return null;
}
}
From another question i got the tip to use a filter instead of the contained handled redirect to the login page, and store the URL before redirect as an attribute in the request like this:
public class LoginFilter implements Filter {
private String loginPage = "/login.jsf";
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,
ServletException {
if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// is session expire control required for this request?
if (httpServletRequest.getUserPrincipal() == null) {
// User is not logged in, redirect to login page.
httpServletRequest.setAttribute("from", httpServletRequest.getRequestURI());
httpServletResponse.sendRedirect(loginPage);
}
else
filterChain.doFilter(request, response);
}
}
#Override
public void destroy() {
}
}
With the url-pattern set to the same as the sum of all security constraints. The problem is how to combine this with the container based login. Leaving login-config auth method as FORM causes the filter to not be executed. Removing it sets the auth-method to BASIC which 1. causes my form to not appear, and 2. httpServletRequest.getUserPrincipal() is automatically set by the web browser to a cached value, so even if the filter is executed, the if-statement will always be false. From what i know, there is no way to keep the browser from doing this, even if the session is invalidated.
Is there any solution to this?