I've read through a few questions related to this topic ( Jersey REST API as a separate web app, Should web service be separate from web site?), but I still struggle to understand which design practice would work best for an existing application.
I inherited a java web application built on spring and hibernate JPA. It's currently in production with new features being developed.
Concurrently, I will need to design a REST API that will have some form of authentication/user tracking. The web application has its own user authentication system that is likely going to be different than the API implementation (i.e. username/pw vs api keys (?)).
Given this situation, I think it'd be best to develop them separately, but I feel like in the beginning, there will be a lot of code duplication (as a result of all the jpa implementation in the web application). Ideally, once I have the rest api in place, I would switch the web application to use the API as well and remove most of the backend code that currently handles the data retrieval.
Before I start down this route though, I was wondering, is there a better way to do this?
you can use Spring Security and create a custom AuthenticationProvider . You can use a JNDI lookup to get the authservice directly from the Container it self.
Example:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private AuthService authService;
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
// use the credentials to try to authenticate against the third party system
if (authService(name, password)) {
List<GrantedAuthority> grantedAuths = new ArrayList<>();
return new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
} else {
throw new AuthenticationException("Unable to auth against third party systems");
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
Also, read more about RESTful apis using Spring here:
http://www.baeldung.com/rest-with-spring-series/
Related
I'd like users in two different realms (eg human users and S2S users) to access the same rest endpoint. All of multi-tenancy examples I can find (eg keycloak multi-tenancy docs) suggest implementing a KeycloakConfigResolver to pick a single realm based on the request path. Eg:
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
private final KeycloakDeployment realm1Deployment;
private final KeycloakDeployment realm2Deployment;
public PathBasedKeycloakConfigResolver() throws IOException {
realm1Deployment = buildDeployment("realm1.json");
realm2Deployment = buildDeployment("realm2.json");
}
#Override
public KeycloakDeployment resolve(HttpFacade.Request request) {
String path = request.getRelativePath();
return path.startsWith("clients/") ? realm1Deployment : realm2Deployment;
}
private static KeycloakDeployment buildDeployment(String path) throws IOException {
return KeycloakDeploymentBuilder.build(new ClasspathResource(path).getInputStream());
}
}
But this requires me to pick a single realm per request path.
I want different functionality, I'd like to try authenticating the request against multiple realms and pick the first the succeeds. I feel this would be the logical way to support multiple realms for a single URI but I'm open to suggestions for achieving this.
Since Keycloak provides OAuth2 functionality, you do not necessarily need to use the keycloak adapters (a lot of them are being deprecated because of this, even, see here). Instead you can just rely on the built in functionality of Spring Security.
An example of how to configure JWT Authentication for Spring Security with multiple issuers looks like this:
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver
("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.authenticationManagerResolver(authenticationManagerResolver)
);
The separate issuer URLs in your case would be the issuer URLs of your respective realms. This example is taken directly from the Spring Security documentation, it also contains samples on how to achieve the same with XML configuration, should you prefer to use that.
Of course, migrating away from the adapter, if you're already using it might not be easy, but since the adapter is going away in the long term anyways, it might be worth evaluating doing so as early as possible
The Keycloak adapters deprecation is announced there.
You should have a look at this OpenID adapter I wrote. It works out of the box with as many issuers as you need and solves quite a few of keycloak spring-boot adapter limitations:
compatible with webmvc (servlets) and webflux (reactive) apps
spring boot 3 ready (does not extend WebSecurityConfigurerAdapter)
no adherence to Keycloak (works with any OpenID authorization-server)
tooling for security unit testing
Basic tutorial here.
I have implemented OIDC authentication in my Spring Boot web application by adding the spring-boot-starter-oauth2-client dependency and configuring OAuth2 client settings in application.properties.
In the Spring Boot and OAuth2 guide there is a section "How to Add a Local User Database":
How to Add a Local User Database
Many applications need to hold data
about their users locally, even if authentication is delegated to an
external provider. We don’t show the code here, but it is easy to do
in two steps.
Choose a backend for your database, and set up some repositories
(using Spring Data, say) for a custom User object that suits your
needs and can be populated, fully or partially, from external
authentication.
Implement and expose OAuth2UserService to call the Authorization
Server as well as your database. Your implementation can delegate to
the default implementation, which will do the heavy lifting of calling
the Authorization Server. Your implementation should return something
that extends your custom User object and implements OAuth2User.
Hint: add a field in the User object to link to a unique identifier in
the external provider (not the user’s name, but something that’s
unique to the account in the external provider).
I have searched a bit but I have not found a code example for the scenario described in the excerpt.
What is the best way to implement the scenario above?
I guess the main parts would be:
On OIDC login, automatically create a user in the database if it does not exist
The web application controller methods have access to the database object that represents the logged-in user
Update:
The guide has a github issue comment that suggests to look at the custom-error sample from the guide's source code. I guess the first part (on OIDC login, automatically create a user if one does not exist) can be done after the call to DefaultOAuth2UserService().loadUser(request). But what about the second part - how can my custom db-backed-user-object be made available to my web application's controller methods?
#Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService(WebClient rest) {
DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
return request -> {
OAuth2User user = delegate.loadUser(request);
if (!"github".equals(request.getClientRegistration().getRegistrationId())) {
return user;
}
OAuth2AuthorizedClient client = new OAuth2AuthorizedClient
(request.getClientRegistration(), user.getName(), request.getAccessToken());
String url = user.getAttribute("organizations_url");
List<Map<String, Object>> orgs = rest
.get().uri(url)
.attributes(oauth2AuthorizedClient(client))
.retrieve()
.bodyToMono(List.class)
.block();
if (orgs.stream().anyMatch(org -> "spring-projects".equals(org.get("login")))) {
return user;
}
throw new OAuth2AuthenticationException(new OAuth2Error("invalid_token", "Not in Spring Team", ""));
};
}
Github uses OAuth2UserService<OAuth2UserRequest, OAuth2User> what you need is OAuth2UserService<OidcUserRequest, OidcUser>. So
did you try creating another #Bean which plugs into the correct place spring expects?
If not, create one like this
#Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser user = delegate.loadUser(userRequest);
log.info("User from oauth server: " + user);
//OAuth2AccessToken accessToken = userRequest.getAccessToken();
//Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
//Fetch the authority information from the protected resource using accessToken
//Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities
//Create a copy of user using mappedAuthorities
//Insert/update local DB
//user = new DefaultOidcUser(mappedAuthorities, user.getIdToken(), user.getUserInfo());
return user;
};
}
I'm pretty new to the concept of patterns. I am practising my dependency injection skills as well as using DAO principles. The code I have written works but I feel that it can be written in a more elegant fashion. I've tried restructuring it a pattern I saw but that complicated things so not sure if I implemented it correctly. As a general rule when a web application communicates with a database and throws out result, how should one structure their project?
I've heard of the MVC principle but that doesn't necessarily add database to the mix.
This is what I have so far:
A class containing a controller in a Controller package:
#RestController
public class ResponseController {
#Autowired
MongoBase dbConnection;
#RequestMapping(value = "/jsonresult", method = RequestMethod.GET)
#ResponseBody
public String jsonresult(#RequestParam(value = "id", required = true) String id){
return dbConnection.documentToJSON(id, Constants.database,Constants.collection);
}
#RequestMapping(value = "/alljsonresult", method = RequestMethod.GET)
#ResponseBody
public String alljsonresult(){
return dbConnection.allDocumentToJSON(Constants.database,Constants.collection);
}}
A class containing CRUD methods to the database in a Database package:
#Component
public class MongoBase {
#Autowired
MongoClient mongoClient;
public MongoBase() {
try {
mongoClient = new MongoClient("localhost", 27017);
} catch (Exception e) {
e.printStackTrace();
}
}
public void printAllCollection(String databaseName, String collectionName) {
...
}
So is there a better way/more efficient way of writing thi? Also I feel I haven't fully implemented DI in the Monogbase class since it contains the new keyword..
If you are using springboot, then you don't need this old style
also don't need to create mongoClient bean your self, spring boot help you in it
You just need to add following properties in application.properties file
#mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=app1
Also declares a spring-boot-starter-data-mongodb in your pom or gradle
it's a cool and super awesome dependency for accessing Data with MongoDB
you can read about it from here[https://spring.io/guides/gs/accessing-data-mongodb/]
suppose you have a domain
#Document(collection = "domain")
public class User {
#Id
private long id;
#Indexed(unique = true)
private String domain;
private boolean displayAds;
//getters and setters
}
Now if we need to perform curd operation on this domain, extends MongoRepository, you have CRUD function automatically. Spring data come with many magic findBy queries, review the official Spring data MongoDB – Query methods for detail.
public interface UserRepository extends MongoRepository<User, Long> {
Domain findFirstByDomain(String domain);
Domain findByDomainAndDisplayAds(String domain, boolean displayAds);
//Supports native JSON query string
#Query("{domain:'?0'}")
Domain findCustomByDomain(String domain);
#Query("{domain: { $regex: ?0 } })")
List<Domain> findCustomByRegExDomain(String domain);
}
UserRepository extends the MongoRepository interface and plugs in the type of values and id it works with: User and Long. Out-of-the-box, this interface comes with many operations, including standard CRUD operations (create-read-update-delete).
now you can easly use it in your controller
#RestController
public class ResponseController {
#Autowired
UserRepository userRepository;
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
User create(#RequestBody #Valid User user) {
return userRepository.create(user);
}
}
also you can do with it lot of things. you just need to go throw with it doc.
Also you you can use mongoTemplate for execute the query
#Autowired
MongoTemplate mongoTemplate;
When I build web applications I typically define the full chain as follows:
Client Side:
View - This is the V in MVC where you control visuals & user action derived workflow.
Controller - This is the C in MVC where workflow is managed. Most Client processing will go here and multiple Client calls can be made to get/send data or perform lookups.
Client - This is where you make a call to a REST web service and parse/deserialize the results/handle exceptions.
Server Side:
RestController (Sometimes Called Resource) - This is your REST API endpoint. Here you extract & validate a request.
Service - This is where most of your server logic will go. Sometimes you might have to make multiple data access calls or call other service functions.
DataAccessObject (Sometimes Called Provider) - This is your database interaction to pull data from your database into a model. CRUD operations (Create Read Update Delete)
Example Scenario:
Lets say we want to submit data & permissions for a given user
UserView.jsp - User types in user & permission data and hits submit.
UserController.java - validates User & permission data, does any necessary lookups, then calls UserClient.
UserClient.java - Builds the REST request and calls the /user/create REST endpoint.
UserRestController.java - Unpackages/Validates the request, then calls UserManagementService
UserManagementService.java - Server Logic happens here! Lets say I have two tables in my database. A User table and a Permissions table. I want to store the user information in the User table and the permission information in the permission table so I will call the UserDAO for the user data and the PermissionDAO for the permission data.
UserDAO & PermissionDAO - Saves The passed models to their respective tables.
Return to Service, Return to RestController, Return to Client (Parse Response), Return to Controller (Move the Workflow forward with a redirect or a success message).
Conclusion:
This may seem like a lot of in-between steps but this design provides a ton of flexibility, especially if your building large, complex web services. Each component has a specific purpose, follows an easy naming convention, and splits complex logic into smaller, simpler steps.
I'd like to recommend some improvements to your solution:
You're using Spring. You should not create any injected beans using new. Let Spring instantiate and manage those beans for you.
Use the #Repository annotation to mark your persistence class.
Make your repository class interface based.
Don't embed "Mongo" into the class name. You happen to be using Mongo as your persistence provider now, but you may change your mind later. Don't reveal implementation information in your class names - hide it.
The Controller is part of the UI. It uses repositories and/or services to fulfill use cases. It's perfectly correct to use Spring to inject the repository into the Controller.
I'd recommend that you use Spring Boot, an opinionated version of Spring. Have a look at their guides to learn how to use it properly.
I am trying to design an API Manager with RESTful webservice. In Spring's new release, we can combine everything in Java code without using web.xml nor securityconfig.xml.
According to Authtoken concept, API manager should have authtoken and refresh token for user authentication.
Please, can anyone give me sample source code or guidance how to implement RESTfull webservice with Spring Security.
I need to know how all configurations are implement in Java code.
it should have Authtoken concept also.
This Tutorial Say correct way to do this.
http://www.beingjavaguys.com/2014/10/spring-security-oauth2-integration.html
But Spring Configuration are in Spring.xml file.
I need to put them in to Java level also.
The people at Stormpath have a quite a straightforward solution for achieving Oauth. Please take a look at Using Stormpath for API Authentication.
As a summary, your solution will look like this:
You will use the Stormpath Java SDK to easily delegate all your user-management needs.
When the user presses the login button, your front end will send the credentials securely to your backend-end through its REST API.
2.1. By the way, Stormpath greatly enhances all the possibilities here. Instead of having your own login page, you can completely delegate the login/register functionality to Stormpath via its IDSite, or you can also delegate it to the Servlet Plugin. Stormpath also supports Google, Facebook, LinkedIn and Github login.
Your backend will then try to authenticate the user against the Stormpath Backend and will return an access token as a result:
/** This code will throw an Exception if the authentication fails */
public void postOAuthToken(HttpServletRequest request, HttpServletResponse response) {
Application application = client.getResource(applicationRestUrl, Application.class);
//Getting the authentication result
AccessTokenResult result = (AccessTokenResult) application.authenticateApiRequest(request);
//Here you can get all the user data stored in Stormpath
Account account = accessTokenResult.getAccount();
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
//Return the Access Token
response.getWriter().print(token.toJson());
response.getWriter().flush();
}
Then, for every authenticated request, your backend will do:
/** This is your protected API */
public void sayHello(HttpServletRequest request, HttpServletResponse response) {
Application application = client.getResource(applicationRestUrl, Application.class);
OauthAuthenticationResult result = (OauthAuthenticationResult) application.authenticateOauthRequest(request).execute();
System.out.println(result.getApiKey());
System.out.println(result.getAccount());
//At this point the authorization was successful, you can now allow the actual operation to be executed
doSayHello();
}
All this will not need any special Spring Security configuration, this is plain Java code that you can run in any framework.
Please take a look here for more information.
Hope that helps!
Disclaimer, I am an active Stormpath contributor.
I'm currently investigating OAuth2 with spring-security and spring boot. Although the concept of this protocol is quite clear to me the implementation details are not (spring does not provide many examples and tutorials to work with). Because of that I would be very grateful for answering my questions below:
What is purpose of "password" grant type? OAuth2 specs doesn't mention about it. Is it just Spring implementation of some kind "authorization shortcut"?
How does resource server handle access tokens (check if it is still valid, scope etc.)? Does I need to implement something or it is provided by Spring Security and ResourceServerConfig?
How RS will know which user (not client) has requested resources? Specific user resources are bound with ids, unique usernames and so on, does token have this kind of information? How to I retrieve it in order to use in resources controllers?
Authorization server (correct me if I'm wrong) is able to check if Client application has permission to requested resources or not. As I understand it shouldn't be aware of Users (Resources Owners). In situation where I authenticate via Google, Facebook or some other service user authentication is their case. What about application where OAuth2 and Resources Server are one application (I'm currently developing such one for test purposes), where I should put UserDetailsService? And how combine it in order to authorize client (js generated from app in this case) at first, then user (Resource owner) and generate token? Currenly I have implemented ClientDetailService and injected to configuration. Where should I inject UserDetailService?
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private MongoClientDetailsService cds;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(cds);
}
}
Are there some JS libraries that helps with authorization flow for custom applications like hello.js which supports (as far I as know) well known services?
Any help would be appreciated:)
That's a lot of questions; let me start by answering 3:
the grant_type with the value password is the official reserved value for the Resource Owner Password Credentials grant type as shown in the spec here: https://www.rfc-editor.org/rfc/rfc6749#section-4.3.2 so it is not Spring specific or custom
the RS can validate the token itself if it is self-contained and structured (e.g. a JWT) or else it will need to make a callback to the Authorization Server to validate it
the validation result from step 2. may include information about the user (or: Resource Owner) who granted access to the client