Spring Security - Default Tables not created - spring

I'am trying to integrate Spring Social on top of Spring Security in a Spring Boot application. But it seems like Spring Security is having issues creating the default tables, e.g. UserConnection, UserProfile, etc since I get these SQL errors after the connection to an oauth2 provider was successfully established:
PreparedStatementCallback; bad SQL grammar [select userId from UserConnection where providerId = ? and providerUserId = ?]; nested exception is org.h2.jdbc.JdbcSQLException: Tabelle "USERCONNECTION" nicht gefunden Table "USERCONNECTION" not found; SQL statement: select userId from UserConnection where providerId = ? and providerUserId = ? [42102-185]
This is a static SQL call in the spring provided JdbcUsersConnectionRepository. I tried to switch over to the InMemory implementation which avoids the SQL problem, but then the next one occurs:
PreparedStatementCallback; bad SQL grammar [INSERT into userProfile(userId, email, firstName, lastName, name, username) values(?,?,?,?,?,?)]; nested exception is org.h2.jdbc.JdbcSQLException: Tabelle "USERPROFILE" nicht gefunden Table "USERPROFILE" not found; SQL statement: INSERT into userProfile(userId, email, firstName, lastName, name, username) values(?,?,?,?,?,?) [42102-185]
The USERPROFILE Table is missing, too.
Before I post tons of configuration snippets, do you already know something I might have forgotten which tells spring to create these tables for me? :)
At the moment I am going with the Spring Boot standard H2 in-memory database, which works well with JpaRepositories.
Thank You! :)

Found the solution myself :)
I eventually found the very first thing wich is not handled by some fancy automagically Spring mechanism but with a plain 'schema.sql' in the src/main/resources directory.
create table UserConnection (
userId varchar(255) not null,
providerId varchar(255) not null,
providerUserId varchar(255),
rank int not null,
displayName varchar(255),
profileUrl varchar(512),
imageUrl varchar(512),
accessToken varchar(1024) not null,
secret varchar(255),
refreshToken varchar(255),
expireTime bigint,
primary key (userId, providerId, providerUserId));
create unique index UserConnectionRank on UserConnection(userId, providerId, rank);
create table UserProfile (
userId varchar(255) not null,
email varchar(255),
firstName varchar(255),
lastName varchar(255),
name varchar(255),
username varchar(255),
primary key (userId));
create unique index UserProfilePK on UserProfile(userId);

Related

insert data from sql file H2 database spring boot

I'm trying to insert data from sql file using h2 database and spring boot .
when I add the sql file into src/main/ressources, I succeeded to create the table and insert data into it.
but when I create a model class named Employee which refer to the table, I can create the tables but there is no rows inserted .
SQL file:
CREATE TABLE employees ( id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(250) NOT NULL, last_name VARCHAR(250) NOT NULL,
mail VARCHAR(250) NOT NULL, password VARCHAR(250) NOT NULL );
INSERT INTO employees (first_name, last_name, mail, password) VALUES
('Laurent', 'GINA', 'laurentgina#mail.com', 'laurent');
model:
import javax.persistence.Column; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import
javax.persistence.GenerationType; import javax.persistence.Id; import
javax.persistence.Table;
import lombok.Data;
#Data #Entity #Table(name = "employees")
public class Employee {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="first_name")
private String first_name;
#Column(name="last_name")
private String last_name;
private String mail;
private String password;
}
application.properties
#Global configuration
spring.application.name=api
#Tomcat configuration
server.port=9000
#Log level configuration
logging.level.root=ERROR
logging.level.com.openclassrooms=INFO
logging.level.org.springframework.boot.autoconfigure.h2=INFO
logging.level.org.springframework.boot.web.embedded.tomcat=INFO
#H2 Configuration
spring.h2.console.enabled=true
There are many ways to initialize the database with spring boot:
Initialize a Database Using JPA
Initialize a Database Using Hibernate
Initialize a Database using basic SQL scripts
For your information: you should separate the schema from the data,
so you should have 2 basic scripts:
schema.sql : In this file you can put your instruction to create table.
CREATE TABLE employees ( id INT AUTO_INCREMENT PRIMARY KEY,first_name VARCHAR(250) NOT NULL, last_name VARCHAR(250) NOT NULL,mail VARCHAR(250) NOT NULL, password VARCHAR(250) NOT NULL );
data.sql : In this file you can put your instruction to insert data
INSERT INTO employees (first_name, last_name, mail, password) VALUES ('Laurent', 'GINA', 'laurentgina#mail.com', 'laurent');
if you choose to use the schema.sql : you shoud use this property spring.jpa.hibernate.ddl-auto=none.
otherwise (Hibernate) you shoud use this property spring.jpa.hibernate.ddl-auto=create-drop
For your information:
Note: spring boot version <= 2.4.x you can choose Hibernate to create the schema or use schema.sql, but you cannot do both.
Note: spring boot version >= 2.5.x if you want script-based DataSource initialization to be able to build upon the schema creation performed by Hibernate, set spring.jpa.defer-datasource-initialization to true.
Be careful it depends on which version you choose!
There are a few things that could be causing this issue.
First, make sure that your SQL file is located in the src/main/resources directory. If it is not, then the file will not be picked up by Spring Boot.
Next, check the permissions on the file. If the file is not readable by the application, then it will not be able to load the data.
Finally, make sure that the SQL file is formatted correctly. If there are any syntax errors in the file, then Spring Boot will not be able to load the data.

Bidirectional mapping not working since it's not saving correctly

I am new to Spring and I am testing the API on postman and the instructor_id is not saving.
This is how I am testing it on postman and don't know if it is right or not.
{
"coursename":"tesasdasdast",
"description":"tesdasdsadasting",
"userEntity":{
"instructor_id":1
}
}
Steps:
I have two entities:
UserEntity
CourseEntity
I have a controller where I'm saving the information called:
CourseController
I have a repository called CourseRepo and I am extending JpaRepository
In CourseEntity:
#ManyToOne
#JoinColumn(name = "instructor_id")
private UserEntity userEntity;
In UserEntity:
#OneToMany(mappedBy = "userEntity", cascade=CascadeType.ALL)
private List<CourseEntity> courseEntity;
In my CourseController:
#PostMapping("/courses")
void addCourse(#RequestBody CourseEntity course) {
courseRepository.save(course);
}
I have added in my pom.xml:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
This is the error message that I'm getting in postman:
{
"timestamp": "2019-10-10T16:51:47.780+0000",
"status": 500,
"error": "Internal Server Error",
"message": "org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.finaly.projectback.entity.CourseEntity.userEntity -> com.finaly.projectback.entity.UserEntity; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.finaly.projectback.entity.CourseEntity.userEntity -> com.finaly.projectback.entity.UserEntity",
"path": "/project/courses"
}
And these two are the tables in the database:
create table web_user(
id INT primary key auto_increment,
firstname VARCHAR(50),
lastname VARCHAR(50),
username VARCHAR(50),
email VARCHAR(50),
pwd VARCHAR(50),
user_role_id INT,
FOREIGN KEY (user_role_id) REFERENCES web_user_role(id)
);
CREATE TABLE web_course (
id INT PRIMARY KEY AUTO_INCREMENT,
coursename VARCHAR(50),
instructor_id INT,
FOREIGN KEY (instructor_id) REFERENCES web_user(id)
);
Thank you in advance for any advice.
Please check if you are correctly setting entities in associations.
userEntity.setCourseEntity and courseEntity.setUserEntity
Do you have this code in place and then check your hibernate queries that are fired on save method call.
I found my mistake. Instead of creating the foreign key as user_entity_user_id, i was creating it as user_id.
It seems like a stupid mistake but I'm still new to Spring and for now, many things look like magic.
Thanks everyone who tried to help.

Spring Boot 2.1.1 Issue Accessing Tables in PostgreSQL that are within Oauth2

I am trying to add postgresql support for OAuth2 with Spring Boot after following some examples to clean up my code.
The problem is that I have to add a schema manually to my own schema scripts for the database to create despite specifying certain properties in the latest Spring Boot. Only after doing so do the tables become recognizable. Also, OAuth2 continues to fail, not finding any table. The issue seems schema related.
I was able to get my own schema to be recognized without specifying one in the entity by disabling auto configuration but cannot figure out why OAuth2 tables are not found unless I use the public schema.
I have added the following properties file with attempts to get Spring boot to recognize my schemas:
server.port=8081
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
# The SQL dialect makes Hibernate generate better SQL for the chosen database
# Hibernate ddl auto (create, create-drop, validate, update)
spring.datasource.jdbcUrl=jdbc:postgresql://xxxxxx:xxx/oauth2
spring.datasource.username= xxxxx
spring.datasource.password= xxxxx
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=20
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.poolName=SpringBootJPAHikariCP
spring.datasource.hikari.maxLifetime=2000000
spring.datasource.hikari.connectionTimeout=30000
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true;
spring.jpa.properties.hibernate.current_session_context_class=thread
spring.jpa.hibernate.ddl-auto=none
spring.datasource.tomcat.default-auto-commit=true
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQL95Dialect
spring.jpa.hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql=true
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.search.autoregister_listeners=false
spring.jpa.properties.hibernate.bytecode.use_reflection_optimizer=false
spring.jpa.properties.hibernate.default_schema = public
# spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
# spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# Hibernate ddl auto (create, create-drop, validate, update)
spring.thymeleaf.templateResolverOrder=1
logging.level.org.springframework=INFO
entitymanager.packagesToScan = com.si.model
logging.level.org.springframework.web=DEBUG
logging.level.guru.springframework.controllers=DEBUG
logging.level.org.hibernate=INFO
spring.main.allow-bean-definition-overriding=true
spring.thymeleaf.cache=false
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.datasource.schema=classpath:schema.sql
spring.datasource.initialization-mode=always
spring.jpa.properties.hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.template.cache: false
spring.jpa.properties.hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
I have also tried setting the Data Source for each object in the Authorization Server:
#Configuration
#EnableAuthorizationServer
class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
def oauthDataSource: DataSource = DataSourceBuilder.create.build
#Autowired
private var authenticationManager: AuthenticationManager = null
#Bean
def clientDetailsService = new JdbcClientDetailsService(oauthDataSource)
#Bean
def tokenStore = new JdbcTokenStore(oauthDataSource)
#Bean
def approvalStore = new JdbcApprovalStore(oauthDataSource)
#Bean
def authorizationCodeServices = new JdbcAuthorizationCodeServices(oauthDataSource)
#Bean
def passwordEncoder(): Pbkdf2PasswordEncoder = new Pbkdf2PasswordEncoder()
#throws[Exception]
override def configure(clients: ClientDetailsServiceConfigurer): Unit = {
clients.jdbc(oauthDataSource)
}
#throws[Exception]
override def configure(oauthServer: AuthorizationServerSecurityConfigurer): Unit = {
oauthServer.passwordEncoder(passwordEncoder)
}
#throws[Exception]
override def configure(endpoints: AuthorizationServerEndpointsConfigurer): Unit = {
endpoints
.authenticationManager(authenticationManager)
.approvalStore(approvalStore)
.authorizationCodeServices(authorizationCodeServices)
.tokenStore(tokenStore)
}
}
Finally, I set up my web configuration as follows:
class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private var passwordEncoder: Pbkdf2PasswordEncoder = null
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
def dataSource: DataSource = DataSourceBuilder.create.`type`(classOf[HikariDataSource]).build
#Bean
#throws[Exception]
override def authenticationManagerBean: AuthenticationManager = super.authenticationManagerBean
#Bean
#throws[Exception]
override def userDetailsServiceBean = new JdbcUserDetails()
#throws[Exception]
override def configure(web: WebSecurity): Unit = {
web.ignoring.antMatchers("/webjars/**", "/resources/**")
}
#throws[Exception]
override protected def configure(http: HttpSecurity): Unit = {
http
.csrf().disable()
.authorizeRequests
.antMatchers("/login", "/logout.do")
.permitAll
.antMatchers("/**")
.authenticated
.and.
formLogin
.loginProcessingUrl("/login.do")
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/login")
.and
.logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout.do"))
.and
.userDetailsService(userDetailsServiceBean)
}
#throws[Exception]
override protected def configure(auth: AuthenticationManagerBuilder): Unit = {
auth
.userDetailsService(userDetailsServiceBean)
.passwordEncoder(passwordEncoder)
}
}
For some reason, I had to set my schemas to public in the schema script:
drop table if exists public.oauth_client_token cascade;
create table if not exists public.oauth_client_token (
token_id VARCHAR(255) not null primary key,
token bytea,
authentication_id VARCHAR(255),
user_name VARCHAR(255),
client_id VARCHAR(255)
);
drop table if exists public.oauth_client_details cascade;
CREATE TABLE if not exists public.oauth_client_details (
client_id varchar(255) NOT NULL primary key,
resource_ids varchar(255) DEFAULT NULL,
client_secret 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 integer,
refresh_token_validity integer,
additional_information varchar(255) DEFAULT NULL,
autoapprove varchar(255) DEFAULT NULL
);
drop table if exists public.oauth_access_token cascade;
create table if not exists public.oauth_access_token(
token_id VARCHAR(255),
token bytea,
authentication_id VARCHAR(255),
user_name VARCHAR(255),
client_id VARCHAR(255),
authentication bytea,
refresh_token VARCHAR(255)
);
drop table if exists public.oauth_refresh_token cascade;
create table if not exists public.oauth_refresh_token(
token_id VARCHAR(255),
token bytea,
authentication bytea
);
drop table if exists public.authorities cascade;
CREATE TABLE if not exists public.authorities (
id bigserial not null primary key,
authority varchar(255)
);
drop table if exists public.credentials cascade;
CREATE TABLE if not exists public.credentials (
id bigserial not null primary key,
enabled boolean not null,
name varchar(255) not null,
password varchar(255) not null,
version integer
);
drop table if exists public.credentials_authorities cascade;
CREATE TABLE if not exists public.credentials_authorities (
credentials_id bigint not null,
authorities_id bigint not null
);
drop table if exists public.oauth_code cascade;
create table if not exists public.oauth_code (
code VARCHAR(255),
authentication bytea
);
drop table if exists public.oauth_approvals cascade;
create table if not exists public.oauth_approvals (
userId VARCHAR(255),
clientId VARCHAR(255),
scope VARCHAR(255),
status VARCHAR(10),
expiresAt timestamp without time zone,
lastModifiedAt timestamp without time zone
);
Access to the oauth2 tables from the clientDetailsRepository or Oauth2 application results in errors such as the following:
org.postgresql.util.PSQLException: ERROR: relation "oauth_client_details" does not exist
As a last resort, I set the search path in postgresql to public for my user and still get this error.
UPDATE
The following query works in pgadmin4 and is the source of my failure:
select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from oauth_client_details order by client_id
Any ideas as to why this happens? How can I resolve this?

value of the foreign key as null in spring mvc hibernet using postgresql

I am using spring mvc hibernate with postgresql.I have created two tables employee and accounts in which there is one to many mapping from employee to accounts,and the employee id is passed as the foreign key to accounts table, but i think the id is not generating. In the database table is generated of accounts table with the foriegn key as the employee id which is the primary key of the employee table, but with null value.
for table generation
#GeneratedValue(strategy = GenerationType.IDENTITY)

Spring Security JDBC authentication default schema error when using PostgreSQL

Is it really impossible to use default schema for Spring Security with PostgreSQL, because the part "varchar_ignorecase" does not exist can't be replaced?
I'm just testing the default settings:
auth.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema();
And below is the error:
Caused by:
org.springframework.beans.factory.BeanDefinitionStoreException:
Factory method [public javax.servlet.Filter
org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain()
throws java.lang.Exception] threw exception;
nested exception is
org.springframework.jdbc.datasource.init.ScriptStatementFailedException:
Failed to execute SQL script statement at line 1 of resource class
path resource
[org/springframework/security/core/userdetails/jdbc/users.ddl]: create
table users(username varchar_ignorecase(50) not null primary
key,password varchar_ignorecase(500) not null,enabled boolean not
null);
nested exception is
org.postgresql.util.PSQLException: ERROR:
type "varchar_ignorecase" does not exist
Cause the default schema is not suitable for PostgreSQL, I need to create my own schema and implement own query for user and authority query.
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username,password, enabled from users where username=?")
.authoritiesByUsernameQuery(
"select username, role from user_roles where username=?");
There is no need to adding withDefaultSchema(). simply define your schema.sql and data.sql with proper column names and foreign key constraints. Following is the example configuration for Mysql (in the Spring Boot).
schema.sql
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS authorities;
CREATE TABLE users
(
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL,
enabled TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY (username)
);
CREATE TABLE authorities
(
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL,
FOREIGN KEY (username) REFERENCES users (username)
);
Then define users and authorities (data.sql)
INSERT INTO users (username, password, enabled)
values ('user','pass',1);
INSERT INTO authorities (username, authority)
values ('user', 'ROLE_USER');
finally, define the authentication mechanism
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.dataSource(dataSource);
}
Schema for PGSQL:
schema.sql
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS authorities;
CREATE TABLE users
(
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL,
enabled INT NOT NULL DEFAULT 1,
PRIMARY KEY (username)
);
CREATE TABLE authorities
(
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL,
FOREIGN KEY (username) REFERENCES users (username)
);
User injection on data.sql
INSERT INTO users (username, password, enabled)
values ('user','pass',1);
INSERT INTO authorities (username, authority)
values ('user', 'ROLE_USER');
Thanks to Mr.Q. I totally used your MySQL schema and adapted it for PGSQL.

Resources