Java spring boot Consider defining a bean of UserService in your configuration - spring

I'm trying to create my first JavaSpring Security Application but getting This error:
Consider defining a bean of type 'de.JBR.mongo.models.UserService' in your configuration.
This is My Sprinboot application Class:
#ComponentScan({ "de.JBR.mongo.repositry", "de.JBR.mongo.api.models", "security.config", "security"})
#EnableMongoRepositories("de.JBR.mongo")
#SpringBootApplication
#AllArgsConstructor
public class EssensManagerApplication {
private final UserRepositry repositry;
public static void main(String[] args) {
SpringApplication.run(EssensManagerApplication.class, args);
}}
My de.JBR.mongo.models.UserService Class:
#AllArgsConstructor
#Service
public class UserService implements UserDetailsService{
private final static String USER_NOT_FOUND = "Nutzer mit Name %s nicht gefunden";
private final UserRepositry repositry;
#Override
#Bean
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return repositry.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException(String.format(USER_NOT_FOUND, username)));
}
}

Since you have added a #ComponentScan and de.JBR.mongo.models is not in the list of packages, your service is not automatically created by Spring. So, either create a #Bean in a configuration file or add the package to the #ComponentScan list.

Related

Spring interface injection from external jar

I have spring API based authentication classes in external library,
Below are some of the classes in external library,
package com.security;
import org.springframework.security.authentication.AuthenticationProvider;
#Component
public class ApiKeyAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(ApiKeyAuthenticationProvider.class);
private ApiAuthCredentialsConfig apiAuthCredentialsConfig;
public ApiKeyAuthenticationProvider(ApiAuthCredentialsConfig apiAuthCredentialsConfig) {
this.apiAuthCredentialsConfig = apiAuthCredentialsConfig;
}
}
ApiAuthCredentialsConfig:
package com.security;
public interface ApiAuthCredentialsConfig {
String getAuthToken();
String getAuthTokenHeaderName();
}
And in the repo I have added the above external library as a gradle dependency.
I have below changes in actual repo.
#Component
#Data
public class ApiAuthenticationConfig implements ApiAuthCredentialsConfig {
#Value("${auth-token}")
private String authToken;
#Value("${auth-token-header-name}")
private String authTokenHeaderName;
}
SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApiKeyAuthenticationProvider apiKeyAuthenticationProvider;
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.
antMatcher("/**").
csrf().disable().
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
and().addFilterBefore(new ApiKeyAuthenticationFilter(authenticationManager(), apiKeyAuthenticationProvider.getHeaderName()), AnonymousAuthenticationFilter.class)
.authorizeRequests().anyRequest().authenticated();
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Collections.singletonList(apiKeyAuthenticationProvider));
}
}
Application:
#SpringBootApplication(scanBasePackages = {"com.security"})
#EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
When I run the application its failing with below error
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.security.ApiKeyAuthenticationProvider required a bean of type 'com.security.ApiAuthCredentialsConfig' that could not be found.
How to resolve this issue?
After the above comment, I realized that ApiAuthenticationConfig is not in the same package as ApiAuthCredentialsConfig, after I moved ApiAuthenticationConfig to com.security package it started working.

Spring Boot app requires a bean annotated with #Primary to start

I'm seeing the following message on a Spring Boot app startup:
> *************************** APPLICATION FAILED TO START
> ***************************
>
> Description:
>
> Field oauthProps in com.example.authservice.AuthorizationServerConfig
> required a single bean, but 2 were found:
> - OAuthProperties: defined in file [/Users/simeonleyzerzon/abc/spring-security/spring-security-5-oauth-client/auth-service/target/classes/com/example/authservice/config/OAuthProperties.class]
> - kai-com.example.authservice.config.OAuthProperties: defined in null
>
>
> Action:
>
> Consider marking one of the beans as #Primary, updating the consumer
> to accept multiple beans, or using #Qualifier to identify the bean
> that should be consumed
I'm wondering what's causing the duplication of that bean and how one can remove it without the necessity of using the #Primary annotation? Not sure where the kai-com package(?) from the above is coming from.
Here's the bean in question:
package com.example.authservice.config;
//#Primary
#Component
#ConfigurationProperties(prefix="kai")
#Setter #Getter
public class OAuthProperties {
private String[] redirectUris;
private String clientId;
private String clientSecret;
private final Token token = new Token();
#Setter #Getter
public static class Token{
private String value;
private String type="";
}
}
and the app/config, etc.:
package com.example.authservice;
import ...
#SpringBootApplication
public class AuthServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServiceApplication.class, args);
}
}
#Controller
class MainController {
#GetMapping("/")
String index() {
return "index";
}
}
#RestController
class ProfileRestController {
#GetMapping("/resources/userinfo")
Map<String, String> profile(Principal principal) {
return Collections.singletonMap("name", principal.getName());
}
}
#Configuration
#EnableResourceServer
class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/resources/**")
.authorizeRequests()
.mvcMatchers("/resources/userinfo").access("#oauth2.hasScope('profile')");
}
}
#Configuration
#EnableAuthorizationServer
#EnableConfigurationProperties(OAuthProperties.class)
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired private OAuthProperties oauthProps;
private final AuthenticationManager authenticationManager;
AuthorizationServerConfig(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(oauthProps.getClientId())
.secret(oauthProps.getClientSecret())
.authorizedGrantTypes("authorization_code")
.scopes("profile")
.redirectUris(oauthProps.getRedirectUris());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(this.authenticationManager);
if (oauthProps.getToken().getType().equals("jwt")) {
endpoints.tokenStore(this.tokenStore()).accessTokenConverter(jwtAccessTokenConverter());
}else {
endpoints.tokenEnhancer(eapiTokenEnhancer());
}
}
TokenEnhancer eapiTokenEnhancer() {
return new TokenEnhancer() {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
result.setValue(oauthProps.getToken().getValue());
return result;
}
};
}
#Bean
JwtAccessTokenConverter jwtAccessTokenConverter() {
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource(".keystore-oauth2-demo"), //keystore
"admin1234".toCharArray()); //storepass
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setKeyPair(factory.getKeyPair("oauth2-demo-key")); //alias
return jwtAccessTokenConverter;
}
#Bean
TokenStore tokenStore() {
return new JwtTokenStore(this.jwtAccessTokenConverter());
}
}
#Service
class SimpleUserDetailsService implements UserDetailsService {
private final Map<String, UserDetails> users = new ConcurrentHashMap<>();
SimpleUserDetailsService() {
Arrays.asList("josh", "rob", "joe")
.forEach(username -> this.users.putIfAbsent(
username, new User(username, "pw", true, true, true, true, AuthorityUtils.createAuthorityList("USER","ACTUATOR"))));
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return this.users.get(username);
}
}
#Configuration
#EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
Eclipse too seems to be only aware of a single instance of the bean:
When using #EnableConfigurationProperties with #ConfigurationProperties you will get a bean named <prefix>-<fqn>, the kai-com.example.authservice.config.OAuthProperties. (See also the reference guide).
When the #ConfigurationProperties bean is registered that way, the bean has a conventional name: <prefix>-<fqn>, where <prefix> is the environment key prefix specified in the #ConfigurationProperties annotation and <fqn> is the fully qualified name of the bean. If the annotation does not provide any prefix, only the fully qualified name of the bean is used.
The bean name in the example above is acme-com.example.AcmeProperties. (From the Reference Guide).
The #Component will lead to another registration of the bean with the regular name of the classname with a lowercase character. The other instance of your properties.
the #EnableConfigurationProperties annotation is also automatically applied to your project so that any existing bean annotated with #ConfigurationProperties is configured from the Environment. You could shortcut MyConfiguration by making sure AcmeProperties is already a bean, as shown in the following example: (From the Reference Guide).
The key here is that #EnableConfigurationProperties is already globally applied and processes any bean annotated with #ConfigurationProperties.
So basically you where mixing the 2 ways of using #ConfigurationProperties and Spring Boot 2 now prevents that misuse. This way you write better code (and reduce the memory footprint and performance slightly).
So either remove the #Component or remove the #EnableConfigurationProperties, either way will work.
The following change (removing of #EnableConfigurationProperties) seems to help relieving the need for the #Primary annotation:
#Configuration
#EnableAuthorizationServer
//#EnableConfigurationProperties(OAuthProperties.class)
class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired private OAuthProperties oauthProps;
Perhaps someone can describe the internal Spring mechanics of secondary bean creation (and its namespace/package assignment) by that annotation which seemingly causes the collision with the #Autowired one, or point me to the appropriate documentation of this behavior.

Spring boot mongoDB autowired null repository

I am experimenting with spring and MongoDB.
In my project I have a repository and a service which has a scheduled method.
The problem is, that the repository doesn't get autowired, it is always null.
Autowire works correctly in the main application class (tested it by implementing CommandLineRunner )
The service is found by componentScan (the constructor is called)
Am I missing somethig?
directory
MachineApplication.java
#SpringBootApplication
#EnableScheduling
public class MachineApplication {
public static void main(String[] args) {
SpringApplication.run(MachineApplication.class, args);
}
}
Worker.java
#Service
public class Worker {
#Autowired
private LineDataRepository lineDataRepository;
#Autowired
private LineRepository lineRepository;
...
public Worker() {
System.out.println("--------------------------------");
System.out.println(lineDataRepository);//null
System.out.println(lineRepository);//null
}
}
LineDataRepository
#Repository
public interface LineDataRepository extends MongoRepository<LineData, String> {
}
Add #EnableMongoRepositories to the MachineApplication to let it detect Mongo repositories.
See here
I think you haven't create mongoDbFactory and mongoTemplate bean, without this bean no connection will be made to your mongoDB. Below is the configuration:
#Configuration
public class MongoConfiguration {
#SuppressWarnings("deprecation")
#Bean
public MongoDbFactory mongoDbFactory() throws Exception {
UserCredentials userCredentials = new UserCredentials("admin", "password");
return new SimpleMongoDbFactory(new Mongo(), "myspring", userCredentials);
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

How to inject property values into Spring Boot beans

In my spring boot application, i'am trying to inject variable's value from the config file application.properties to my java class and i'm getting a null value.
here is the configuration of my application.properties file:
myapp.username=user#user.com
myapp.password=user
here is where i call the configuration entries:
#Component
public class MyClass{
#Value("${myapp.username}")
public String username;
#Value("${myapp.password}")
public String password;
public static void main(String[] args) {
System.out.println(password);
}
}
I hope there someone how did deal with the same problem, thanks.
you can use this example add bean to your config like this :
#Configuration
#ComponentScan(basePackages = "youpackagebase")
#PropertySource(value = { "classpath:application.properties" })
public class AppConfig {
/*
* PropertySourcesPlaceHolderConfigurer Bean only required for #Value("{}") annotations.
* Remove this bean if you are not using #Value annotations for injecting properties.
*/
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
and in your bean :
#Component
public class NetClient {
#Value("${bigwater.api_config.url.login}")
public String url_login;
Best Regards
You are not even letting the Spring Boot container to boot (initialize) as you are are writing the code directly under main.
You should have an Application class as shown below to launch the Spring boot container properly, look here.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As far as my understanding you wanted to execute your code once the container is started, so follow the below steps:
Add the above Application class and then in your NetClient component class add a #Postconstruct method & this method will be called automatically once the bean is ready, refer the code below:
#Component
public class NetClient {
#Value("${bigwater.api_config.url.login}")
public String url_login;
#Value("${bigwater.api_config.url.ws}")
public static String url_ws;
#Value("${bigwater.api_config.username}")
public String username;
#Value("${bigwater.api_config.password}")
public String password;
#Postconstruct
public void init() {
//place all of your main(String[] args) method code here
}
//Add authentification() method here
}

#Autowired does not work with #Configurable

I am trying to do an image upload API. I have a ImageUpload task as follows,
#Component
#Configurable(preConstruction = true)
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ImageUploadTask implements Callable<JSONObject> {
#Autowired
private ImageUploadService imageUploadService;
#Override
public JSONObject call() throws Exception {
....
//Upload image via `imageUploadService`
imageUploadService.getService().path('...').post('...'); // Getting null pointer here for imageUploadService which is a WebTarget
}
}
The ImageUploadService looks like the below,
#Component
public class ImageUploadService {
#Inject
#EndPoint(name="imageservice") //Custom annotation, battle tested and works well for all other services
private WebTarget imageservice;
public WebTarget getService() {
return imageservice;
}
}
Here is the spring boot application class,
#ComponentScan
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAutoConfiguration
public class ImageApplication extends SpringBootServletInitializer {
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new RequestContextListener());
}
public static void main(String[] args) throws IOException {
SpringApplication.run(ImageApplication.class);
}
}
Additional information :
Spring version of dependencies are at 4.2.5.RELEASE
pom.xml has dependencies added for spring-aspects and
spring-instrument
I am getting a NullPointerException in ImageUploadTask. My suspicion is that #Autowired doesn't work as expected.
Why wouldn't work and how do I fix this?
Is it mandatory to use #Autowired only when I use #Conigurable, why not use #Inject? (though I tried it and getting same NPE)
By default the autowiring for the #Configurable is off i.e. Autowire.NO beacuse of which the imageUploadService is null
Thus update the code to explicity enable it either as BY_NAME or BY_TYPE as below.
#Component
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ImageUploadTask implements Callable<JSONObject> { .... }
Rest of the configuration viz. enabling load time weaving seems fine.
Also regarding #Inject annotation have a look here which pretty much explains the difference (or similarity perhaps)

Resources