Java - Token flow OAuth 2 E2E with code - java

I'm New to security & JAVA and I need to implement token follow of OAuth2, this is the exact flow which I need to implement (if there is some library which can help it's great )
http://tutorials.jenkov.com/oauth2/authorization-code-request-response.html
How can I achieve it with JAVA, I want to use some library that provide this functionality. the token flow should be against the UAA but any other similar example will be very helpful.
i've found this example but not sure how to use/test it E2E with UAA
Postman will be very helpful to simulate it...
https://developers.google.com/api-client-library/java/google-oauth-java-client/oauth2
UAA context
https://github.com/cloudfoundry/uaa

I would suggest you Spring as the most popular framework for building web apps in Java. It has Spring Security module that can facilitate developing OAuth 2.0 clients as well as resource servers, as shown here or here.

For a detailed explanation of the OAuth 2.0 flow, visit RFC 6749 Specification. Regarding a step by step solution, you ought to see some tutorials such as this article explaining how to create a Spring REST API using OAuth 2.0. This article goes through code as well as creating Postman requests. With regards to mocking/tests, I've previously created a test suite for the OAuth 2.0 using TestNG and Mockito.
The more you develop and research, the more you shall find ways of improving or rather change the way you design your code. That said if you really want to abide by the OAuth 2.0 flow, you should properly understand the flow (which can be relatively vague at times) in the RFC 6749 link.

Here is the Google API clinet library sample. Try this if it helps
public class ServletSample extends AbstractAuthorizationCodeServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// do stuff
}
#Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
#Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(),
new NetHttpTransport(),
new JacksonFactory(),
new GenericUrl("https://server.example.com/token"),
new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"),
"s6BhdRkqt3",
"https://server.example.com/authorize").setCredentialDataStore(
StoredCredential.getDefaultDataStore(
new FileDataStoreFactory(new File("datastoredir"))))
.build();
}
#Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
public class ServletCallbackSample extends AbstractAuthorizationCodeCallbackServlet {
#Override
protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
throws ServletException, IOException {
resp.sendRedirect("/");
}
#Override
protected void onError(
HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
throws ServletException, IOException {
// handle error
}
#Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
#Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(),
new NetHttpTransport(),
new JacksonFactory(),
new GenericUrl("https://server.example.com/token"),
new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"),
"s6BhdRkqt3",
"https://server.example.com/authorize").setCredentialDataStore(
StoredCredential.getDefaultDataStore(
new FileDataStoreFactory(new File("datastoredir"))))
.build();
}
#Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}

https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth2 contains sample code for performing oauth2 using Spring Security.

Related

Adding separate custom Servlet in Vaadin 23 - Spring 2.7.1

This question was already asked, however since then all answers (that I could found) are no longer valid.
Essentially I want to implement a website with Vaadin (V23), that communicates with a WebApp via POST requests that is running on another server (physically). To do it, I want to create separate Servlet that would handle the communication (receiving side) with another Server. Let's say, this is not implemneted version:
#WebServlet(urlPatterns = "/communication", name = "QuizServlet", asyncSupported = true)
public class QuizServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(400, "Not implemented");
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(400, "Not implemented");
}
}
The problem is however, that I always get redirected to default dispatcher Servlet, and it seems, regardless of what I do:
SpringVaadinServlet was deprecated and no longer exists, extending VaadinServlet does not work.
Changing mappings in properties (vaadin.url-mapping=) also does not work, I just get redirected to this new mapping in all cases.
Trying to do servlets on separate ports yields same redirection on all ports, even if explicitly registering my custom Servlet on the Connector, with separate Sevice (WebMvcConfigurer Tomcat configuration). Answer from this post, also too old.
Registering servlet directly also does not do anything (by implementing WebApplicationInitializer).
There for the question, how to make use of two different servlets with new Vaadin 23 and Spring Boot 2.7.1?
I have found some kind of a solution to my problem. Namely on startup of my BootAplication, I am also starting the second separate Tomcat server that uses my custom Servlet :
#Service
public class QuizServer {
private final Log log = LogFactory.getLog(QuizServer.class);
#PostConstruct
public void startServer() throws IOException, LifecycleException {
start();
}
private void start() throws IOException, LifecycleException {
Tomcat tomcat = new Tomcat();
String contextPath = "/";
String appBase = new File(".").getAbsolutePath();
Context ctx = tomcat.addContext(contextPath, appBase);
Tomcat.addServlet(ctx, "quizServlet", new QuizServlet());
ctx.addServletMappingDecoded("/*", "quizServlet");
tomcat.setPort(8085);
tomcat.start();
tomcat.getConnector();
log.info("Quiz server started");
}
}
#WebServlet(urlPatterns = "/*", name = "quizServlet", asyncSupported = true)
public class QuizServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("Test");
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(400, "Not implemented");
}
}
It is a bit crude though, since ideally, it shouldn't require a separate server.

Web application deployed not generating authorization tokens

I'm trying send using gmail api with oauth2 credentials like below
private Credential getCredentials(NetHttpTransport httpTransport) throws IOException {
// Load client secrets.
try {
Resource file = resourceLoader.getResource("classpath:credentials.json");
InputStream inputStream = file.getInputStream();
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(inputStream));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY,
clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline").build();
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
} catch (Exception exception) {
exception.printStackTrace();
LOGGER.info("Exception occured:: {}", exception.getMessage());
throw new RecordNotFoundException(exception.getMessage());
}
}
using desktop app's credentials.json file.
When I have deployed in dev server I am unable to generate access and refresh token saved file.
Could you please help me.
AuthorizationCodeInstalledApp OAuth 2.0 authorization code flow for an installed Java application that persists end-user credentials.
You cant deploy that to a server its going to open the authorization window on the server.
For a web application it looks like you should be following this Oauth
public class CalendarServletSample extends AbstractAuthorizationCodeServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// do stuff
}
#Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
#Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(), JacksonFactory.getDefaultInstance(),
"[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
#Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
public class CalendarServletCallbackSample extends AbstractAuthorizationCodeCallbackServlet {
#Override
protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
throws ServletException, IOException {
resp.sendRedirect("/");
}
#Override
protected void onError(
HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
throws ServletException, IOException {
// handle error
}
#Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
#Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(), JacksonFactory.getDefaultInstance()
"[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
#Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
From what I have understood from your question and comments you want to achieve the following:
With your current code send email messages from your application which already works on your local machine and now you want to do it too in a web server.
Considering that you are the only user that needs to authorise the application you can achieve what you are aiming using service accounts.
A service account works best for applications like yours where you don't need authorization from your users but rather from your account to for example send emails automatically.
These type of accounts belong to your application rather than to an individual user and can make API requests without the need to authorise through the UI. This guide from the documentation will walk you step through step on how to set up your authorization with service accounts.
Moreover, bare in mind that in order for the service account to execute requests in your name (as you need an user to send emails) you should use domain-wide authorization so that the service account can make such requests in the name of the user. Also note that you need a Google Workspace account to implement domain wide authorization (let me know if you don't have it as I can propose a workaround).

Dialogflow Fulfillment for Java client library

I am migrating our dialog flow agent to use V2 API. Our V1 implementation uses Java client library from dialog-flow(api-ai). Our web service receives the request on webhook endpoint which is configured to invoke 'doWebook' method.
Below is the V1 implementation where I use AIWebhookRequest and Fulfillment
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Fulfillment output = new Fulfillment();
doWebhook(gson.fromJson(request.getReader(), AIWebhookRequest.class), output);
response.setCharacterEncoding(RESPONSE_CHARACTER_ENCODING);
response.setContentType("application/json");
gson.toJson(output, response.getWriter());
}
/** handle the actions passed by Google Home intents **/
protected void doWebhook(AIWebhookRequest input, Fulfillment output) {.....}
I am trying to utilize google-cloud-dialogflow-v2 java library now with the following changes
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Fulfillment output = new Fulfillment(); // ** This is still V1, What could I use from V2 here??**
doWebhook(gson.fromJson(request.getReader(), *WebhookRequest*.class), output);
response.setCharacterEncoding(RESPONSE_CHARACTER_ENCODING);
response.setContentType("application/json");
gson.toJson(output, response.getWriter());
}
/** handle the actions passed by Google Home intents **/
protected void doWebhook(*WebhookRequest* input, *WebhookResponse* output) {.....}
My question is on the line
Fulfillment output = new Fulfillment(); // This is still V1, What could I use from V2 here??

graphql-java-servlet's removal of SimpleGraphQLServlet

In an old version of graphql-java-servlet I used to extend SimpleGraphQLServlet and then override GraphQLContext createContext( Optional request, Optional response ) to add a cookie to the response. I would also override GraphQLErrorHandler getGraphQLErrorHandler() to do some custom error handling.
I'm now trying to do a large jump in version to graphql-java-servlet 6.x.
As of graphql-java-servlet 6.x, SimpleGraphQLServlet is gone. There now is a SimpleGraphQLHttpServlet, which I can't use directly.
Unfortunately, though, the github documentation is way out of date and still suggests using SimpleGraphQLServlet even though it is long gone. There are some builders and I can find some very simplistic references outside of the github documentation, but none of them cover my use cases.
I don't want to do anything fancy, but I need to be able to add a cookie to the response and do some custom error handling.
How can I do this in graphql-java-servlet 6.x? I can't seem to find any clarity on this.
There is GraphQLServletListener. It is also described in project docs, although it is a bit wrong (no OperationCallback in code).
Anyway, here is a working piece of code (used com.graphql-java-kickstart:graphql-java-servlet:6.1.4):
GraphQLSchema schema = getSchema();
List<GraphQLServletListener> listeners = new ArrayList<GraphQLServletListener>();
GraphQLServletListener lstnr = new GraphQLServletListener(){
public RequestCallback onRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("onRequest:" + request.getRequestURI());
//TODO cookies here
response.addCookie(new Cookie("sample","test"));
return new RequestCallback() {
#Override
public void onSuccess(HttpServletRequest request, HttpServletResponse response) {
System.out.println("onSuccess:" + request.getRequestURI());
}
#Override
public void onError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) {
//TODO add some error handling here
System.out.println("onError:" + request.getRequestURI());
}
#Override
public void onFinally(HttpServletRequest request, HttpServletResponse response) {
System.out.println("onFinally:" + request.getRequestURI());
}
};
}
};
listeners.add(lstnr);
SimpleGraphQLHttpServlet servlet = SimpleGraphQLHttpServlet.newBuilder(schema)
.withListeners(listeners)
.build();

How to mock answers of the Google App Engine services (e.g. blobstore)

I'm trying to create a unit test for my Google App Engine project. The use case is as follows: a client queries the API for an upload URL, as the data needs to be stored in the blobstore, the client recieves a JSON encoded structure with the URL. The client then uploads the data to that URL.
The implementation of the servlet is fairly simple:
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Gson gson = new Gson();
Map<String, String> result = new HashMap<String, String>();
result.put("uploadurl", BlobstoreServiceFactory.getBlobstoreService()
.createUploadUrl("/api/v1/import"));
gson.toJson(result, resp.getWriter());
}
In good fashion there should be a test to see whether the client does indeed receive the right data. So there should be a counter JUnit test. I was hoping to mock the blob store service so that it would return a fixed upload url, which the test then can check.
However, I have no idea how to overrule the blobstore service. Using Mockito I can't mock the static getBlobstoreService(), using the LocalBlobstoreServiceTestConfig I have no idea how I can overrule the answer to createUploadUrl().
My attempt to write a test was something like this:
public class ImportServletTest {
public static class Response {
String uploadurl;
void setUploadurl(String url) {
this.uploadurl = url;
}
}
private LocalBlobstoreServiceTestConfig blobstoreConfig = new LocalBlobstoreServiceTestConfig();
private LocalServiceTestHelper helper = new LocalServiceTestHelper(blobstoreConfig);
#Test
public void getsUploadURL() throws IOException, ServletException {
ImportServlet servlet = new ImportServlet();
HttpServletResponse response = mock(HttpServletResponse.class);
try (CharArrayWriter output = new CharArrayWriter();
PrintWriter writer = new PrintWriter(output);) {
when(response.getWriter()).thenReturn(writer);
servlet.doGet(null, response);
writer.flush();
Response apiResponse = new Gson().fromJson(output.toString(), Response.class);
assertEquals("http://mysite/_ah/theurl", apiResponse.uploadurl);
}
}
#Before
public void setupGae() throws IOException {
helper.setUp();
}
#After
public void teardownGae() {
helper.tearDown();
}
}
Mocking static classes/methods is in general very dangerous (http://googletesting.blogspot.it/2008/12/static-methods-are-death-to-testability.html), but in a similar case I had some success using PowerMock (https://code.google.com/p/powermock/) to override the behavior of static classes that were not under my control. I guess you'll have to mock the entire method chain:
BlobstoreServiceFactory.getBlobstoreService().createUploadUrl()
to return a custom URL instead of that generated by the BlobStore.

Categories

Resources