How to make OAuth2 server read client from database rather than write in memory? - spring

So I want to find a way to read Client credentials (client_id, client_secret,...) from database. I'm currently using SpringBoot 2.7.3.
Every tutorial I found is from 4+ years ago and use deprecated dependencies.

You are probably using the InMemoryClientRegistrationRepository implementation of the ClientRegistrationRepository interface. If you want to retrieve the clients from another place, you have to create a new implementation of that interface. If you are using Spring Data JPA, you can do something like:
public interface ClientRegistrationSpringDataRepository extends JpaRepository<ClientRegistrationEntity, String> {
}
#Repository
public class DaoClientRegistrationRepository implement ClientRegistrationRepository {
private final ClientRegistrationSpringDataRepository repository;
// constructor
#Override
public ClientRegistration findByRegistrationId(String registrationId) {
ClientRegistrationEntity entity = this.repository.getById(registrationId);
return mapToClientRegistration(entity);
}
private ClientRegistration mapToClientRegistration(ClientRegistrationEntity entity) {
// your logic
}
}

Related

Spring Boot Transaction support using #transactional annotation not working with mongoDB, anyone have solution for this?

Spring Boot version - 2.4.4,
mongodb version - 4.4.4
In my project, I want to do entry in 2 different document of mongodb, but if one fails than it should do rollback. mongodb supports transaction after version 4.0 but only if you have at least one replica set.
In my case I don't have replica set and also cannot create it according to my project structure. I can't use transaction support of mongodb because no replica-set. So, I am using Spring Transaction.
According to spring docs, to use transaction in Spring Boot, you only need to use #transactional annotation and everything will work(i.e. rollback or commit).
I tried many things from many sources but it is not rollbacking transaction if one fail.
Demo code is here,
This is demo code, not actual project.
This is my service class.
#Service
public class UserService {
#Autowired
UserRepository userRepository;
#Autowired
UserDetailRepository userDetailRepository;
#Transactional(rollbackFor = Exception.class)
public ResponseEntity<JsonNode> createUser(SaveUserDetailRequest saveUserDetailRequest) {
try {
User _user = userRepository.save(new User(saveUserDetailRequest.getId(), saveUserDetailRequest.getFirstName(), saveUserDetailRequest.getLastName()));
UserDetail _user_detail = userDetailRepository.save(new UserDetail(saveUserDetailRequest.getPhone(), saveUserDetailRequest.getAddress()));
} catch (Exception m) {
System.out.print("Mongo Exception");
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Also tried below code but still not working,
#EnableTransactionManagement
#Configuration
#EnableMongoRepositories({ "com.test.transaction.repository" })
#ComponentScan({"com.test.transaction.service"})
public class Config extends AbstractMongoClientConfiguration{
private com.mongodb.MongoClient mongoClient;
#Bean
MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
#Bean
public com.mongodb.MongoClient mongodbClient() {
mongoClient = new com.mongodb.MongoClient("mongodb://localhost:27017");
return mongoClient;
}
#Override
protected String getDatabaseName() {
return "test";
}
}
The transaction support in Spring is only there to make things easier, it doesn't replace the transaction support for the underlying datastore being used.
In this case, it will simply delegate the starting/committing of a transaction to MongoDB. WHen using a database it will eventually delegate to the database etc.
As this is the case, the pre-requisites for MongoDB still need to be honoured and you will still need a replica.

Spring Cloud Stream Supplier function model

I am trying to use spring cloud stream and the new functions support for configuration but I am having a problem to understand how to achieve the same result I would have with annotation configuration.
I need to send a message to the brooker, every time a user is created. With the annotation based configuration I could accomplish it like this:
public UserProducer {
#Autowired
private final Source source;
#Autowired
private final UserRepository repository;
public void saveUser(User user) {
repository.save(user);
source.output().send(MessageBuilder.withPayload(user).build());
}
}
Is it possible to use spring cloud stream functions to achieve the same result?
You can use the new StreamBridge API for doing that. See the docs here: https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/3.0.6.RELEASE/reference/html/spring-cloud-stream.html#_using_streambridge

Spring alternative for Factory

May be its a duplicate, Please feel free to tag... I am a newbie to Spring.
I am implementing a UserService for getting user details from different vendors,
So My class Structure is
Interface UserService ->> UserServiceA, UserServiceB
Which user service to use depends upon a field called provider. my code will look something like
public interface ExternalUserService {
ExternalUserDTO getUserDetail(String username);
}
Implementations -
public class GoogleUserService implements ExternalUserService{
#Override
public ExternalUserDTO getUserDetail(String username) {
return user;
}
}
public class FacebookUserService implements ExternalUserService{
#Override
public ExternalUserDTO getUserDetail(String username) {
return user;
}
}
I want to use it in my code in this fashion, I dont know if this is possible, but giving a try to see if its possible
public class ExternalUserManager(String provider) {
String provider;
#Autowired
ExternalUserService service; //This is supposed to come from some factory, dont know how to get it in spring context.
public void doSomething(String username) {
System.out.println(service.getUserDetail(username));
}
}
Had it been in conventional java programming, I would have created a Factory called UserServiceFactory, which would have made the things straight.
Can someone please help me on how much it is possible with spring, and if its possible, then how can I achieve it? We use Spring boot, so no xml config.
You can use a #Bean annotated method with scope 'prototype' as a factory.
Spring will call this method anytime this bean is injected somewhere.
import org.springframework.beans.factory.config.BeanDefinition;
...
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public ExternalUserService externalUserService(UserServiceFactory factory,UserProviderResolver resolver) {
.. create the user service depending on resolver.getProvider()
}
The UserServiceFactory is used to create the specific service depending on the provider name, as you already described.
Create a class UserProviderResolver whith a method getProvider() that returns the provider name for the current request or user.
You can #Autowire the HttpRequest in the UserProviderResolver to get access to the current request.

How can I do relational database-based HTTP Session Persistence in Spring 4?

I need to be able to store the HTTP Session in a relational database in order to do stateless load balancing of my front-end users across multiple front-end servers. How can I achieve this in Spring 4?
I see how one can do this with Redis, however there does not appear to be documentation on how to do this with a relational database e.g. Postgres.
With Spring Session (it transparently will override HttpSessions from Java EE) you can just take SessionRepository interface and implement it with your custom ex. JdbcSessionRepository. It is kind of easy to do. When you have your implementation, then just add manually (you don't need #EnableRedisHttpSession annotation) created filter to filter chain, like bellow:
#Configuration
#EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
//other stuff...
#Autowired
private SessionRepository<ExpiringSession> sessionRepository;
private HttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy(); // or HeaderHttpSessionStrategy
#Bean
public SessionRepository<ExpiringSession> sessionRepository() {
return new JdbcSessionRepository();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
http
.addFilterBefore(sessionRepositoryFilter, ChannelProcessingFilter.class);
}
}
Here you have how SessionRepository interface looks like. It has only 4 methods to implement. For how to create Session object, you can look in MapSessionRepository and MapSession implementation (or RedisOperationsSessionRepository and RedisSession).
public interface SessionRepository<S extends Session> {
S createSession();
void save(S session);
S getSession(String id);
void delete(String id);
}
Example solution https://github.com/Mati20041/spring-session-jpa-repository
Now spring boot supports by 'spring-session-jdbc'. You can save session into db with less code. For more example you can look at https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-jdbc.html#httpsession-jdbc-boot-sample
Just slap Spring Session on it, and you're done. Adding a Redis client bean and annotating a configuration class with #EnableRedisHttpSession is all you need.

Spring Data Neo4J and CDI

I setup Spring Data Neo4J following this tutorial: http://spring.io/guides/gs/accessing-data-neo4j/ and changed this slightly to use it on the Neo4J server and this runs well.
Then I tried to find an example, how I can use the repositories within a CDI environment as outlined in these examples : http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpd.misc.cdi-integration
Merely, I can not find any example what I have to provide to make this run with Neo4J.
So my question is : did anybody try to setup Neo4j with Spring Data and CDI and can provide an example, how I have to set up Spring configuration for CDI and how I can make Repositories accessable for #Inject ? Please consider that I'm pretty new in the Spring Data and Neo4J topic ;)
Thanks in advance !
Joern
At least I found something that seems to work. I extended the Neo4JConfiguration to set up the Neo4J server connection. Within this class I produce also the needed repositories. The repositories itself have to be annotated with #NoRepositoryBean
public class MyNeo4JConfiguration extends Neo4jConfiguration {
GraphDatabaseService graphDatabaseService() {
return new SpringRestGraphDatabase("http://localhost:7474/db/data");
}
public GraphDatabase graphDatabase() {
if (graphDatabaseService() instanceof GraphDatabase)
return (GraphDatabase) graphDatabaseService();
return new DelegatingGraphDatabase(graphDatabaseService());
}
#Produces
PersonRepository getPersonRepository() {
GraphRepositoryFactory factory;
try {
factory = new GraphRepositoryFactory(new Neo4jTemplate(
this.graphDatabase()), this.neo4jMappingContext());
PersonRepository personRepository = factory
.getRepository(PersonRepository.class);
return personRepository;
} catch (Exception e) {
return null;
}
}
The repository :
#NoRepositoryBean
public interface PersonRepository extends GraphRepository<Person> {
Person findByName(String name);
Iterable<Person> findByTeammatesName(String name);
}
The PersonRepository can now be injected with #Inject.
Thanks to this post !!!

Resources