How to handle "TokenEndpoint : Handling error: InvalidScopeException, Empty scope.."? - authorization

everyone!
I've tried to repeat this tutorial https://www.youtube.com/watch?v=wxebTn_a930 to create an Authorization Server and i've received:
"Handling error: InvalidScopeException, Empty scope (either the client or the user is not allowed the requested scopes)" and I don't know why?
So i can't receive an access token from my auth server.
The only difference in my project i use postgreSQL instead of MySQL.
Project has as dependencies: spring boot starter web, spring boot starter cloud security, spring data jpa, spring cloud starter oauth2, postgresql.
Aplication.yml
server:
port: 9020
spring:
datasource:
url: jdbc:postgresql://localhost:5432/oauth
username: root
password: root
driverClassName: org.postgresql.Driver
platform: postgres
initialization-mode: never
# JPA config
jpa:
database: POSTGRESQL
hibernate.ddl-auto: validate
check-user-scopes: true
Models:
#MappedSuperclass
public class BaseIdEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;
}
#Entity(name = "permission")
public class Permission extends BaseIdEntity {
private String name;
// Getters and Setters
}
#Entity(name = "role")
public class Role extends BaseIdEntity {
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "permission_role", joinColumns = {
#JoinColumn(name = "role_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "permission_id", referencedColumnName = "id")})
private List<Permission> permissions;
private String name;
// Getters and Setters
}
#Entity(name = "users")
public class User extends BaseIdEntity implements UserDetails {
private static final long serialVersionUID = 1L;
private String email;
private String username;
private String password;
private boolean enabled;
#Column(name = "account_locked")
private boolean accountNonLocked;
#Column(name = "account_expired")
private boolean accountNonExpired;
#Column(name = "credentials_expired")
private boolean credentialsNonExpired;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "role_user", joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "id")})
private List<Role> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<>();
roles.forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role.getName()));
role.getPermissions().forEach(permission -> {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
});
});
return null;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
#Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
#Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
#Override
public boolean isEnabled() {
return enabled;
}
public String getEmail() {
return email;
}
}
Repository:
#Repository
#Transactional
public interface UserRepository extends JpaRepository<User, Long> {
User findUserByUsername(String username);
}
Class CustomUserDetailsService which implements UserDetailsService and overrides all methods.
#Service(value = "userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findUserByUsername(username);
if (user == null)
throw new BadCredentialsException("Bad Credentials");
new AccountStatusUserDetailsChecker().check(user);
return user;
}
}
Web security configurations.
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().exceptionHandling()
.authenticationEntryPoint((httpServletRequest, httpServletResponse, authException) ->
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and().authorizeRequests().antMatchers("/**")
.authenticated().and().httpBasic();
}
}
Class CustomTokenEnhancer which adds additional information about user like email.
public class CustomTokenEnhancer extends JwtAccessTokenConverter {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
Map<String, Object> info = new LinkedHashMap<>(accessToken.getAdditionalInformation());
info.put("email", user.getEmail());
DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
customAccessToken.setAdditionalInformation(info);
return super.enhance(customAccessToken, authentication);
}
}
CustomOauth2RequestFactory represents a filter which creates a token requests before any user requests.
public class CustomOauth2RequestFactory extends DefaultOAuth2RequestFactory {
#Autowired
private TokenStore tokenStore;
#Autowired
UserDetailsService userDetailsService;
public CustomOauth2RequestFactory(ClientDetailsService clientDetailsService) {
super(clientDetailsService);
}
#Override
public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
if (requestParameters.get("grant_type").equals("refresh_token")) {
OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(
tokenStore.readRefreshToken(requestParameters.get("refresh_token")));
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken(authentication.getName(), null,
userDetailsService.loadUserByUsername(authentication.getName()).getAuthorities()));
}
return super.createTokenRequest(requestParameters, authenticatedClient);
}
}
And configurations for authorization server.
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${check-user-scopes}")
private Boolean checkUserScopes;
#Autowired
private DataSource dataSource;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Bean
public OAuth2RequestFactory requestFactory() {
CustomOauth2RequestFactory requestFactory = new CustomOauth2RequestFactory(clientDetailsService);
requestFactory.setCheckUserScopes(true);
return requestFactory;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new CustomTokenEnhancer();
converter.setKeyPair(
new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"),
"password".toCharArray()).getKeyPair("jwt"));
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
}
#Bean
public TokenEndpointAuthenticationFilter tokenEndpointAuthenticationFilter() {
return new TokenEndpointAuthenticationFilter(authenticationManager, requestFactory());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtAccessTokenConverter())
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
if (checkUserScopes)
endpoints.requestFactory(requestFactory());
}
}
scheme-postgres.sql.
DROP TABLE IF EXISTS oauth_client_details CASCADE;
CREATE TABLE oauth_client_details(
client_id VARCHAR(255) NOT NULL PRIMARY KEY,
client_secret VARCHAR(255) NOT NULL,
resource_ids VARCHAR(255) DEFAULT NULL,
scope VARCHAR(255) DEFAULT NULL,
authorized_grant_types VARCHAR(255) DEFAULT NULL,
web_server_redirect_uri VARCHAR(255) DEFAULT NULL,
authorities VARCHAR(255) DEFAULT NULL,
access_token_validity INT DEFAULT NULL,
refresh_token_validity INT DEFAULT NULL,
additional_information VARCHAR(4096) DEFAULT NULL,
autoapprove VARCHAR(255) DEFAULT NULL);
DROP TABLE IF EXISTS permission CASCADE;
CREATE TABLE permission (
id int PRIMARY KEY,
name VARCHAR(60) UNIQUE);
DROP TABLE IF EXISTS role CASCADE;
CREATE TABLE role
(id int PRIMARY KEY,
name VARCHAR(60) UNIQUE);
DROP TABLE IF EXISTS permission_role CASCADE;
CREATE TABLE permission_role(
permission_id int,
FOREIGN KEY(permission_id) REFERENCES permission(id),
role_id int,
FOREIGN KEY(role_id) REFERENCES role(id));
DROP TABLE IF EXISTS users CASCADE;
CREATE TABLE users (
id int PRIMARY KEY,
username VARCHAR(24) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
enabled boolean NOT NULL,
account_locked boolean NOT NULL,
account_expired boolean NOT NULL,
credentials_expired boolean NOT NULL);
DROP TABLE IF EXISTS role_users CASCADE;
CREATE TABLE role_users (role_id int,FOREIGN KEY(role_id) REFERENCES role(id),
users_id int, FOREIGN KEY(users_id) REFERENCES users(id));
data-postgres.sql
INSERT INTO oauth_client_details (
client_id,client_secret,
resource_ids,
scope,
authorized_grant_types,
web_server_redirect_uri,authorities,
access_token_validity,refresh_token_validity,
additional_information,autoapprove)
VALUES(
'USER_CLIENT_APP','{bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi',
'USER_CLIENT_RESOURCE,USER_ADMIN_RESOURCE',
'role_admin,role_user',
'authorization_code,password,refresh_token,implicit',
NULL,NULL,
900,3600,
'{}',NULL);
INSERT INTO permission (name) VALUES
('can_create_user'),
('can_update_user'),
('can_read_user'),
('can_delete_user');
INSERT INTO role (name) VALUES
('role_admin'),('role_user');
INSERT INTO permission_role (permission_id, role_id) VALUES
(1,1), /* can_create_user assigned to role_admin */
(2,1), /* can_update_user assigned to role_admin */
(3,1), /* can_read_user assigned to role_admin */
(4,1), /* can_delete_user assigned to role_admin */
(3,2); /* can_read_user assigned to role_user */
INSERT INTO users (
username,password,
email,enabled,account_locked, account_expired,credentials_expired) VALUES (
'admin','{bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi',
'william#gmail.com',true,true,true,true),
('user','{bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi',
'john#gmail.com',true,true,true,true);
INSERT INTO role_users (role_id, users_id)
VALUES
(1, 1) /* role_admin assigned to admin user */,
(2, 2) /* role_user assigned to user user */ ;

The problem was in model "User":
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<>();
roles.forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role.getName()));
role.getPermissions().forEach(permission -> {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
});
});
return null;
}
The method returned "null" instead of "authorities". Silly mistake.

Related

Spring Security login always returns with a 302 redirect to the failureUrl

I created a project in Spring Security and React, I set up the security configuration, and I created a password encoder, the endpoints work but the login always returns me with a 302 redirect to the failureUrl.
This is some parts of source code
this is a part of SecurityConfiguration.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity( prePostEnabled = true )
public class SecurityConfiguration {
private final CustomerServiceImplementation customerService;
public SecurityConfiguration( CustomerServiceImplementation service ) {
this.customerService = service;
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return (
http
.cors()
.and()
.csrf( csrf -> csrf.disable() )
.authorizeRequests( auth ->
auth
.antMatchers("/api/v1/customer/signup").permitAll()
.antMatchers("/api/v1/role").permitAll()
// public routes
.antMatchers("/public").permitAll()
.antMatchers("/public/**").permitAll()
// FrontEnd
.antMatchers("/").permitAll()
.antMatchers("/**/*.png").permitAll()
.anyRequest().authenticated()
)
.formLogin()
.usernameParameter("email")
.passwordParameter("password")
.loginPage("/public/sign-in")
.loginProcessingUrl("/public/login")
.permitAll()
.successHandler( authenticationSuccessHandler() )
.defaultSuccessUrl("/")
.failureHandler( authenticationFailureHandler() )
.failureUrl("/public/sign-in?error=true")
.permitAll()
.and()
.logout()
.logoutUrl("/sign-out")
.logoutSuccessUrl("/")
.permitAll()
.userDetailsService( customerService )
.exceptionHandling( ex ->
ex
.accessDeniedHandler( accessDeniedHandler() )
)
.headers(headers -> headers.frameOptions().sameOrigin())
.httpBasic(withDefaults())
.build()
);
}
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new AppAuthenticationFailureHandler();
}
#Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new AppAuthenticationSuccessHandler();
}
#Bean
public AccessDeniedHandler accessDeniedHandler() {
return new AppAccessDeniedHandler();
}
}
this is a part of CustomerServiceImplementation.java
#Service
public class CustomerServiceImplementation implements CustomerService, UserDetailsService {
#Autowired
private CustomerRepository customerRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return
customerRepository
.findByEmail( username )
.map( Customer::new )
.orElseThrow( () -> new UsernameNotFoundException("email not exist") )
;
}
}
this is a part of Customer.java
#Data
#AllArgsConstructor
#Entity
#Table( name = "customers" )
public class Customer implements UserDetails {
#Id
#GeneratedValue( strategy = GenerationType.SEQUENCE )
private Long id;
#Column(
unique = true,
nullable = false,
length = 255
)
private String email;
#Column( nullable = false, length = 128 )
private String password;
private String phoneNumber;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
#Column( nullable = false )
private LocalDate dob;
public Customer() {
}
public Customer(Customer customer) {
this.id = customer.getId();
this.email = customer.getEmail();
this.dob = customer.getDob();
this.roles = customer.getRoles();
}
#ManyToMany(
fetch = FetchType.EAGER
// cascade = CascadeType.ALL
)
#JoinTable(
name = "customers_roles",
joinColumns = #JoinColumn( name = "customer_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn( name = "role_id", referencedColumnName = "id")
)
private Collection<Role> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
getRoles()
.stream()
.map( role -> role.getName() )
.forEach( roleName -> {
authorities.add( new SimpleGrantedAuthority( roleName ));
})
;
return authorities;
}
}

cannot convert from 'TableDependency.SqlClient.Base.Enums.DmlTriggerType' to 'TableDependency.SqlClient.Base.Abstracts.ITableDependencyFilter'

I'm trying to follow this tutorial, but getting this error
Argument 6: cannot convert from
'TableDependency.SqlClient.Base.Enums.DmlTriggerType' to
'TableDependency.SqlClient.Base.Abstracts.ITableDependencyFilter'
(CS1503)
Also, in the same tutorial author used Hubcontext in startup file like this
services.AddScoped<IHubContext<NonProductionHub>, HubContext<NonProductionHub>>();
I'm not sure to whether its correct or not because I'm getting the following error on HubContext and not on IHubContext
The type or namespace name 'HubContext<>' could not be found (are you
missing a using directive or an assembly reference?)
public class InventoryDatabaseSubscription : IDatabaseSubscription
{
private bool disposedValue = false;
private readonly IInventoryRepository _repository;
private readonly IHubContext<NonProductionHub> _hubContext;
private SqlTableDependency<Apps> _tableDependency;
public InventoryDatabaseSubscription(IInventoryRepository repository, IHubContext<NonProductionHub> hubContext)
{
_repository = repository;
_hubContext = hubContext;
}
public void Configure(string DefaultConnection)
{
_tableDependency = new SqlTableDependency<Apps>(DefaultConnection, null, null, null, null, DmlTriggerType.All);
_tableDependency.OnChanged += Changed;
_tableDependency.OnError += TableDependency_OnError;
_tableDependency.Start();
Console.WriteLine("Waiting for receiving notifications...");
}
private void TableDependency_OnError(object sender, ErrorEventArgs e)
{
Console.WriteLine($"SqlTableDependency error: {e.Error.Message}");
}
private void Changed(object sender, RecordChangedEventArgs<Apps> e)
{
if (e.ChangeType != ChangeType.None)
{
// TODO: manage the changed entity
var changedEntity = e.Entity;
_hubContext.Clients.All.SendAsync("UpdateCatalog", _repository.Apps);
}
}
#region IDisposable
~InventoryDatabaseSubscription()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_tableDependency.Stop();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
Argument 6: cannot convert from 'TableDependency.SqlClient.Base.Enums.DmlTriggerType' to 'TableDependency.SqlClient.Base.Abstracts.ITableDependencyFilter' (CS1503)
From the error , you could go to the definition of SqlTableDependency method to check the arguments contained
public SqlTableDependency(string connectionString, string tableName = null, string schemaName = null,
IModelToTableMapper<T> mapper = null, IUpdateOfModel<T> updateOf = null,
ITableDependencyFilter filter = null, DmlTriggerType notifyOn = DmlTriggerType.All,
bool executeUserPermissionCheck = true, bool includeOldValues = false);
The value DmlTriggerType.All should be the seventh instead of sixth, and the value of the sixth parameter is null , change the code like below :
_tableDependency = new SqlTableDependency<Apps>(DefaultConnection, null, null, null, null, null, DmlTriggerType.All);
The type or namespace name 'HubContext<>' could not be found (are you missing a using directive or an assembly reference?)
The HubContext allows you to send messages to your connected clients. It has many of the same features to communicate with clients as when you are inside of a Hub.
In order to get an instance of the HubContext, you need to be using dependency injection by specifying you want an IHubContext<T> in the constructor. Where T is your Hub. Refer to the following example :
public class HomeController : Controller
{
private readonly IHubContext<NotificationHub> _hubContext;
public HomeController(IHubContext<NotificationHub> hubContext)
{
_hubContext = hubContext;
}
}
Referece :https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-2.2

Hazelcast: Does Portable Serialization needs objects to be shared between client and server?

I am getting the below exception:
Could not find PortableFactory for factory-id: 1
com.hazelcast.nio.serialization.HazelcastSerializationException: Could
not find PortableFactory for factory-id: 1
On the client side I have the following code:
public class ClientTest {
public static void main(String[] args) {
List<String> nodes = new ArrayList<String>();
nodes.add("localhost:5701");
ClientConfig clientConfig = new ClientConfig();
ClientNetworkConfig networkConfig = new ClientNetworkConfig();
networkConfig.setAddresses(nodes);
clientConfig.setNetworkConfig(networkConfig);
SerializationConfig serCong = clientConfig.getSerializationConfig();
serCong.addPortableFactory(1, new UserFactoryImpl());
serCong.setPortableVersion(1);
HazelcastInstance hzClient1 = HazelcastClient.newHazelcastClient(clientConfig);
IMap<String, User> map = hzClient1.getMap("user");
System.out.println(map.size() + "hiten");
User user1 = new User();
user1.setFirstName("hiten");
user1.setLastName("singh");
map.put("1", user1);
//hz1.getLifecycleService().terminate();
System.out.println(map.size() + "after");
User user2 = new User();
user2.setFirstName("hiten1");
user2.setLastName("singh1");
map.put("2", user2);
UserEntryProcessor entryProc = new UserEntryProcessor();
User userRes = (User)map.executeOnKey("1", entryProc);
}
static class UserEntryProcessor implements EntryProcessor<String, User>, HazelcastInstanceAware {
private transient HazelcastInstance hazelcastInstance;
#Override
public Object process(Entry<String, User> entry) {
User user = entry.getValue();
if(user != null) {
System.out.println(user.getFirstName());
}
return user;
}
#Override
public EntryBackupProcessor<String, User> getBackupProcessor() {
return null;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
}
static class UserFactoryImpl implements PortableFactory{
public final static int USER_PORTABLE_ID = 1;
public final static int FACTORY_ID = 1;
public Portable create(int classId) {
switch (classId) {
case USER_PORTABLE_ID:
return new User();
}
return null;
}
}
static class User implements Portable {
private String firstName;
private String lastName;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Override
public int getFactoryId() {
return UserFactoryImpl.FACTORY_ID;
}
#Override
public int getClassId() {
return UserFactoryImpl.USER_PORTABLE_ID;
}
#Override
public void writePortable(PortableWriter writer) throws IOException {
writer.writeUTF("first_name", firstName);
writer.writeUTF("last_name", lastName);
}
#Override
public void readPortable(PortableReader reader) throws IOException {
firstName = reader.readUTF("first_name");
lastName = reader.readUTF("last_name");
}
}
}
Yes it does, just as you figured out the factory and the classes need to be available. Currently there is no built-in solution to not share classes for more sophisticated use cases than simple gets / puts. I have JSON support and some other ideas cooking but nothing really done yet.

How to use BCryptPasswordEncoder on account registration and on account authentication in spring?

I have created a web application based on Spring-Boot 1.2.2.RELEASE. I also have a database table where I manage user credentials. It has the basic columns e.g. id, username, and password. Also added salt column where I plan to store randomly generated salts per account.
I'm trying to use Spring Security and having some difficulty with authentication using the encoded password. So basically I have a Register Controller:
#Autowired
private UserRepository userRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity<User> register(#RequestParam(value = "email_address") String emailAddress, #RequestParam(value = "password") String password) {
String username = emailAddress;
String salt = KeyGenerators.string().generateKey();
User user = new User();
user.setUsername(emailAddress);
user.setEmailAddress(emailAddress);
user.setSalt(salt);
user.setPassword(passwordEncoder.encode(username+salt+password));
user.setCreatedBy(1);
user.setCreatedOn(new Date());
user.setLastUpdatedby(1);
user.setLastUpdatedOn(new Date());
user.setStartDate(new Date());
return new ResponseEntity<User>(this.userRepository.save(user), HttpStatus.OK);
}
Then I implemented UserDetailsService like this:
#Service
protected static class ApplicationUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(username);
if (user == null) {
return null;
}
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
String password = passwordEncoder.encode(username+user.getSalt()+user.getPassword());
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
}
However, since BCryptPasswordEncoder generates new result everytime even if the input is the same, how will it be able to authenticate?
EDIT:
Just wanted to add that if I don't use any encoder and store the password as plain text, I am able to authenticate just fine. But of course that's not what I want to do.
UPDATE 1
Here's config for WebSecurityConfigurerAdapter. Inside it I have the configure method.
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApplicationUserDetailsService applicationUserDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserDetailsService).passwordEncoder(passwordEncoder);
}
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
UPDATE 2
I got it working by extending DaoAuthenticationProvider. See updated code below.
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApplicationUserDetailsService applicationUserDetailsService;
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(applicationUserDetailsService);
authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
return authenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
Also had to modify my RegisterController as shown below.
#RestController
public class RegisterController {
#Autowired
private UserRepository userRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity<User> register(#RequestParam(value = "email_address") String emailAddress, #RequestParam(value = "password") String password) {
User user = new User();
user.setUsername(emailAddress);
user.setEmailAddress(emailAddress);
user.setPassword(passwordEncoder.encode(password));
user.setSalt(KeyGenerators.string().generateKey());
user.setCreatedBy(1);
user.setCreatedOn(new Date());
user.setLastUpdatedby(1);
user.setLastUpdatedOn(new Date());
user.setStartDate(new Date());
return new ResponseEntity<User>(this.userRepository.save(user), HttpStatus.OK);
}
}
UPDATE 3
Forgot to include the updated UserDetailService implementation.
#Service
protected static class ApplicationUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(username);
if (user == null) {
return null;
}
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
String password = passwordEncoder.encode(user.getPassword());
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
}
I might need to remove the salt column now since it's basically useless.
Hopefully this helps others as well.

Hibernate queryexception: could not resolve entity property during JPA query

I am trying to query my hibernate table for a RunEntity. The first where clause in the query searches for RunEntities where the testName = the passed value testname. In the stacktrace, it mentions that it cannot find a match for type testname in the RunEntity, but the RunEntity object explicitly has a string named testName with setters and getters and #Column notation.
Table setup
CREATE TABLE RunEntity (ID INTEGER IDENTITY,TestNumber INTEGER NOT NULL, TestName varchar(50) NOT NULL, ENVIRONMENT VARCHAR(50) NOT NULL, Source VARCHAR(50), Date TIMESTAMP, RESULTFILES BLOB);
Query
#Query("SELECT r FROM RunEntity r WHERE r.testName = :testname AND r.testNumber = :testnumber AND r.environment = :environment AND r.source = :source")
public List<RunEntity> findByNameNumberEnvironmentSource(
#Param("testname") String testname,
#Param("testnumber") int testnumber,
#Param("environment") String environment,
#Param("source") String source);
Entity
package com.web_application;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Lob;
#Entity
#Table(name = "TESTRUNS")
public class RunEntity {
private int ID;
private int testNumber;
private String testName;
private String environment;
private String source;
private String passOrFail;
private Timestamp date;
private byte[] resultFiles;
#Id
#Column(name = "ID")
#GeneratedValue
public int getID()
{
return this.ID;
}
public void setID(int ID){this.ID = ID;}
#Column(name="TestNumber")
public int getTestNumber()
{
return this.testNumber;
}
public void setTestNumber(int testNum){this.testNumber = testNum;}
#Column(name="TestName")
public String testName()
{
return this.testName;
}
public void setTestName(String testName){this.testName = testName;}
#Column(name="Environment")
public String getEnvironment()
{
return this.environment;
}
public void setEnvironment(String enviro){this.environment = enviro;}
#Column(name="Source")
public String getSource()
{
return this.source;
}
public void setSource(String src){this.source = src;}
#Column(name="PassOrFail")
public String getPassOrFail()
{
return this.passOrFail;
}
public void setPassOrFail(String pOrF){this.passOrFail = pOrF;}
#Column(name="Date")
public Timestamp getDate()
{
return this.date;
}
public void setDate(Timestamp dates){this.date = dates;}
#Lob
#Column(name="ResultFiles")
public byte[] getResultFiles()
{
return this.resultFiles;
}
public void setResultFiles(byte[] file){this.resultFiles = file;}
}
Part of stacktrace
Caused by: org.hibernate.QueryException: could not resolve property: testname of: com.web_application.RunEntity [SELECT r FROM com.web_application.RunEntity r WHERE r.testname = :testname AND r.testNumber = :testnumber AND r.environment = :environment AND r.source = :source]
at org.hibernate.QueryException.generateQueryException(QueryException.java:137)
at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:120)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:234)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:126)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:88)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:190)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1800)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:328)
... 66 more
Change this
#Column(name="TestName")
public String testName()
{
return this.testName;
}
to
#Column(name="TestName")
public String getTestName()
{
return this.testName;
}
Property access Naming convention is important.Try to use IDE for example (Eclipse Getter-Setter,instead using manually doing it)
Correct your testName() getter to getTestName(). You are using Property Access and have to stick to JavaBeans convention.