JAAS how to tell Glassfish which LoginModule to use? - glassfish-3

I want to use JAAS Authentification for my webapp.
For that i have the following classes:
UserPrincipal:
import java.security.Principal;
public class UserPrincipal implements Principal {
private String name = "";
public UserPrincipal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
RolePrincipal:
import java.security.Principal;
public class RolePrincipal implements Principal {
private String name = "";
public RolePrincipal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
LoginModule:
public class MyLoginModule implements LoginModule {
private CallbackHandler callbackHandler = null;
private Subject subject = null;
private UserPrincipal userPrincipal = null;
private RolePrincipal rolePrincipal = null;
private String login = null;
private List<String> userGroups = null;
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
this.callbackHandler = callbackHandler;
this.subject = subject;
}
public boolean login() throws LoginException {
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("login");
callbacks[1] = new PasswordCallback("password", true);
try {
callbackHandler.handle(callbacks);
String name = ((NameCallback)callbacks[0]).getName();
String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
if(name != null && name.equals("admin") && password != null && password.equals("admin")) {
this.login = name;
this.userGroups = new ArrayList<String>();
this.userGroups.add("admin");
return true;
}
throw new LoginException("Authentication failed");
} catch (IOException e) {
throw new LoginException(e.getMessage());
} catch (UnsupportedCallbackException e) {
throw new LoginException(e.getMessage());
}
}
public boolean commit() throws LoginException {
this.userPrincipal = new UserPrincipal(this.login);
this.subject.getPrincipals().add(this.userPrincipal);
if(this.userGroups != null && this.userGroups.size() > 0) {
for(String groupName: this.userGroups) {
this.rolePrincipal = new RolePrincipal(groupName);
this.subject.getPrincipals().add(this.rolePrincipal);
}
}
return true;
}
public boolean abort() throws LoginException {
return false;
}
public boolean logout() throws LoginException {
this.subject.getPrincipals().remove(this.userPrincipal);
this.subject.getPrincipals().remove(this.rolePrincipal);
return true;
}
}
How do i have to tell my Glassfish server that he has to use MyLoginModule
as the LoginModule?
My web.xml security configuration is that:
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>admin</role-name>
</security-role>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Admin</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
The Documentation i found is not really clear in what actually to do.
Hope someone knows!

Edit your config/login.conf and add your LoginModule for the realm you use. In your web.xml, you use the "Admin" realm (realm-name). So I guess your login.conf file should look like :
Admin {
com.mycompany.MyLoginModule required;
}

Related

Save data from fragment to custom session

I am creating a project in which I am using navigation drawer and on navigation item click it opens a login page and after login it movies to my main activity. Now, I want to save my login details and all data in my custom shared preference from the fragment. After that it on app restarts and I go to navigation login items it should check if the user is already logged in then it should move to an activity otherwise it should run my login fragment
my login fragment
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
CDSMainViewModel =
ViewModelProviders.of(this).get(CDP_MainViewModel.class);
View root = inflater.inflate(R.layout.fragment_cdplogin, container, false);
context = container.getContext();
context = getActivity().getApplicationContext();
session = new Session(context);
if (session.isLoggedIn()) {
Intent itra = new Intent(getActivity().getApplicationContext(), Verification_Activity.class);
startActivity(itra);
getActivity().finish();
}
else{
login_button = root.findViewById(R.id.button_click_login);
edit1 = root.findViewById(R.id.input_username);
edit2 = root.findViewById(R.id.input_password);
layout_1 = root.findViewById(R.id.usnamelayout);
layout_2 = root.findViewById(R.id.password_layout);
login_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
return root;
}
private void Login_data() {
String URL = "http://117.240.196.238:8080/api/cdp/getAuth";
Log.i("response", URL);
StringRequest jsonObjRequest = new StringRequest(
Request.Method.POST, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("response_login", response);
parseData1(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("volley", "Error: " + error.getMessage());
showServerConnectionError();
}
}) {
#Override
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=UTF-8";
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("AuthID", name);
params.put("AuthPwd", password);
return params;
}
};
RequestQueue queue = SingletonRequestQueue.getInstance(getActivity().getApplicationContext()).getRequestQueue();
queue.add(jsonObjRequest);
}
private void parseData1(String response){
try {
JSONObject json = new JSONObject(response);
int success = json.getInt("success");
String msg = json.getString("message");
if(success == 1){
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
JSONArray recData = json.getJSONArray("data");
for (int i = 0; i < recData.length(); i++) {
JSONObject c = recData.getJSONObject(i);
String uname = name;
String upass = password;
String emp_id = c.getString("emp_id");
String empname = c.getString("EmpName");
String office = c.getString("OfficeNameFull");
String desig = c.getString("DesignationName");
String mobile = c.getString("EmpMobile");
String office_code = c.getString("OfficeCode");
String OfficeType = c.getString("OfficeType");
String district = c.getString("DistrictCode");
String DistrictName = c.getString("DistrictName");
String designationCode = c.getString("designationCode");
String DesignationName1 = c.getString("DesignationName1");
String DesigShortName = c.getString("DesigShortName");
Log.i("session",district);
//Here my loginsession is not working its not saving my data in my session..
Session.getInstance(getContext()).loginsession(emp_id,uname,upass,empname,office,desig,mobile,office_code,OfficeType,district,DistrictName,designationCode,DesignationName1,DesigShortName);
// String email = SessionManager.getInstance(context).getUserEmail();
// session.loginsession(emp_id,uname,upass,empname,office,desig,mobile,office_code,OfficeType,district,DistrictName,designationCode,DesignationName1,DesigShortName);
Intent its12 = new Intent(getActivity().getApplicationContext(), Verification_Activity.class);
startActivity(its12);
getActivity().overridePendingTransition(R.anim.from_right, R.anim.slide_to_left);
getActivity().finish();
}
} else {
Toast.makeText(context,msg, Toast.LENGTH_LONG).show();
}
}catch(Exception ex){
}
}
}
//Session manager class
package com.example.agridept.domain;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import com.example.agridept.ui.CDP_login.CDP_MainFragment;
public class Session {
private static Session jInstance;
SharedPreferences preferences;
SharedPreferences.Editor editor;
Context context;
int PRIVATE_MODE = 0;
private static final String IS_LOGIN = "IsLoggedIn";
private static final String PREF_NAME = "AndroidHivePref";
String emp_id1,username1,password1 ,empname1 , office1 , desig1, mobile1, office_code1, OfficeType1 , district1 ,DistrictName1 , designationCode1, DesignationName11 , DesigShortName1;
public Session(Context context){
this.context = context;
preferences = context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
editor = preferences.edit();
}
public void loginsession(String emp_id,String username,String password11 ,String empname ,String office ,String desig,String mobile,String office_code,String OfficeType ,String district ,String DistrictName ,String designationCode,String DesignationName1 ,String DesigShortName){
editor.putBoolean(IS_LOGIN, true);
editor.putString(emp_id1,emp_id);
editor.putString(username1,username);
editor.putString(password1,password11);
editor.putString(empname1,empname);
editor.putString(office1,office);
editor.putString(desig1,desig);
editor.putString(mobile1,mobile);
editor.putString(office_code1,office_code);
editor.putString(OfficeType1,OfficeType);
editor.putString(district1,district);
editor.putString(DistrictName1,DistrictName);
editor.putString(designationCode1,designationCode);
editor.putString(DesignationName11,DesignationName1);
editor.putString(DesigShortName1,DesigShortName);
}
public boolean isLoggedIn() {
return preferences.getBoolean(IS_LOGIN, false);
}
public void logoutUser() {
// Clearing all data from Shared Preferences
editor.clear();
editor.commit();
// After logout redirect user to Loing Activity
Intent i = new Intent(context, CDP_MainFragment.class);
// Closing all the Activities
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Add new Flag to start new Activity
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Staring Login Activity
context.startActivity(i);
}
public void clearinfo() {
// Clearing all data from Shared Preferences
editor.clear();
editor.commit();
}
public SharedPreferences getPreferences() {
return preferences;
}
public void setPreferences(SharedPreferences preferences) {
this.preferences = preferences;
}
public SharedPreferences.Editor getEditor() {
return editor;
}
public void setEditor(SharedPreferences.Editor editor) {
this.editor = editor;
}
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public int getPRIVATE_MODE() {
return PRIVATE_MODE;
}
public void setPRIVATE_MODE(int PRIVATE_MODE) {
this.PRIVATE_MODE = PRIVATE_MODE;
}
public static String getIsLogin() {
return IS_LOGIN;
}
public static String getPrefName() {
return PREF_NAME;
}
public String getEmp_id1() {
return emp_id1;
}
public void setEmp_id1(String emp_id1) {
this.emp_id1 = emp_id1;
}
public String getPassword1() {
return password1;
}
public void setPassword1(String password1) {
this.password1 = password1;
}
public String getEmpname1() {
return empname1;
}
public void setEmpname1(String empname1) {
this.empname1 = empname1;
}
public String getOffice1() {
return office1;
}
public void setOffice1(String office1) {
this.office1 = office1;
}
public String getDesig1() {
return desig1;
}
public void setDesig1(String desig1) {
this.desig1 = desig1;
}
public String getMobile1() {
return mobile1;
}
public void setMobile1(String mobile1) {
this.mobile1 = mobile1;
}
public String getOffice_code1() {
return office_code1;
}
public void setOffice_code1(String office_code1) {
this.office_code1 = office_code1;
}
public String getOfficeType1() {
return OfficeType1;
}
public void setOfficeType1(String officeType1) {
OfficeType1 = officeType1;
}
public String getDistrict1() {
return district1;
}
public void setDistrict1(String district1) {
this.district1 = district1;
}
public String getDistrictName1() {
return DistrictName1;
}
public void setDistrictName1(String districtName1) {
DistrictName1 = districtName1;
}
public String getDesignationCode1() {
return designationCode1;
}
public void setDesignationCode1(String designationCode1) {
this.designationCode1 = designationCode1;
}
public String getDesignationName11() {
return DesignationName11;
}
public void setDesignationName11(String designationName11) {
DesignationName11 = designationName11;
}
public String getDesigShortName1() {
return DesigShortName1;
}
public void setDesigShortName1(String desigShortName1) {
DesigShortName1 = desigShortName1;
}
public static synchronized Session getInstance(Context context) {
if (jInstance != null) {
return jInstance;
} else {
jInstance = new Session(context);
return jInstance;
}
}
}

ASP.NET Core 2.1 How to pass variables to TypeFilter

I have created this typefilter that is supposed to take 2 variables in order for it to send to a method that is linked to the filter. However, I am unable to attach my 2 variables for it to run.
public class RolesFilterAttribute : TypeFilterAttribute
{
public RolesFilterAttribute() : base(typeof(RolesFilterAttributeImpl))
{
}
private class RolesFilterAttributeImpl : IActionFilter
{
private readonly ValidateRoleClient validateRoleClient;
private string Role;
private string SecretKey;
public RolesFilterAttributeImpl(string Role, string SecretKey, ValidateRoleClient validateRoleClient)
{
this.validateRoleClient = validateRoleClient;
this.Role = Role;
this.SecretKey = SecretKey;
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.HttpContext.Request.Cookies["Token"] != null || context.HttpContext.Request.Cookies["RefreshToken"] != null)
{
TokenViewModel tvm = new TokenViewModel
{
Token = context.HttpContext.Request.Cookies["Token"],
RefreshToken = context.HttpContext.Request.Cookies["RefreshToken"]
};
ValidateRoleViewModel vrvm = new ValidateRoleViewModel
{
Role = Role,
SecretKey = SecretKey,
Token = tvm
};
validateRoleClient.ValidateRole(vrvm);
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
throw new NotImplementedException();
}
}
}
This is how I declare the filter and it compiles fine. However, I am not able to pass the required variables which are SecretKey and Role through it. Is my typefilter declared correctly?
[TypeFilter(typeof(RolesFilterAttribute))]
public IActionResult About()
{
return View();
}
Taken from the official documentation
[TypeFilter(typeof(AddHeaderAttribute),
Arguments = new object[] { "Author", "Steve Smith (#ardalis)" })]
public IActionResult Hi(string name)
{
return Content($"Hi {name}");
}

sqlite-net-extensions -- Create Table Async

My problem is that I'm using the CreateTableAsync method and is always returning "0". I researched and saw that this return is a mistake.
I wanted to know what I'm doing wrong.
Class Service Table:
public class SqliteTable
{
private readonly SqliteWrapper _sqliteWrapper;
public SqliteTable()
{
_sqliteWrapper = new SqliteWrapper();
}
private async Task<bool> CheckIfExistTable<T>() where T : new()
{
var connection = _sqliteWrapper.OpenDatabase();
try
{
var result = await connection.Table<T>().CountAsync();
return result.Equals(0);
}
catch (Exception e)
{
Logs.Logs.Error($"Error get count table {typeof(T).Name}: {e.Message}");
return false;
}
}
public async void CreateTable<T>() where T : new()
{
var connection = _sqliteWrapper.OpenDatabase();
if (await CheckIfExistTable<T>())
{
Logs.Logs.Info($"This table {typeof(T).Name} was created");
return;
}
var createTableResult = await connection.CreateTableAsync<T>();
var value = createTableResult.Results.Values.FirstOrDefault();
if (value.Equals(1))
{
Logs.Logs.Info($"Create table {typeof(T).Name}");
}
else
{
throw new Exception($"Error create table {typeof(T).Name}");
}
}
}
I create a Class Model Login. which would be the object to create the database.
public class Login
{
public Login()
{
}
public Login(string user, string password)
{
User = user;
Password = password;
}
public Login(int id, string user, string password)
{
Id = id;
User = user;
Password = password;
}
[PrimaryKey, AutoIncrement, Column("login_id")]
public int Id { get; set; }
[Unique, NotNull, Column("login_user")]
public string User { get; set; }
[NotNull, Column("login_password")] public string Password { get; set; }
}
I create Class CreateTableAsync. Which would be to intanciar the SqliteTable, to call the method CreateTable sending the object to create the database:
protected override void OnStart()
{
try
{
var sqliteTable = new SqliteTable();
sqliteTable.CreateTable<Login>();
}
catch (Exception e)
{
Logs.Logs.Error($"Error init application: {e.Message}");
}
}
Can someone help me?

Adding spring-boot-starter-web to dependencies breaks multiple datasources

I have a project with 3 different DataSources. It works fine if the project is run from with spring-boot:run only with these dependencies:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>RELEASE</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-web</artifactId>-->
<!--</dependency>-->
Here is one datasource, they are all pretty much the same, just changing bean names and database information
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "emfIntranet", transactionManagerRef = "tmIntranet", basePackages = {"com.vnt.intranet.repositories"})
#ConfigurationProperties(prefix = "databases.sistemas")
public class IntranetPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
#Primary
#Bean(name = "dsIntranet")
public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
private EclipseLinkJpaVendorAdapter getEclipseLinkJpaVendorAdapter() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.PostgreSQLPlatform");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
#Primary
#Bean(name = "emfIntranet")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getEclipseLinkJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("com.vnt.intranet.entities");
factoryBean.setPersistenceUnitName("intranet");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE / FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
#Primary
#Bean(name = "tmIntranet")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
I can access all datasources with no problem... One of them is annotated with #Primary.
But if I uncomment spring-boot-starter-web dependency it breaks it and gives me:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: more than one 'primary' bean found among candidates: [emfIntranet, entityManagerFactory, emfMkRadius, emfMkData]
I'm trying to convert this to a web project with no success...
Any ideas?
EDIT
Adding other classes for clarity:
MkDataPersistence.class
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "emfMkData", transactionManagerRef = "tmMkData", basePackages = {"org.example.mkdata.repositories"})
#ConfigurationProperties(prefix = "databases.mkdata")
public class MkDataPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
#Bean(name = "dsMkData")
javax.sql.DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
#Bean
HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
#Bean(name = "emfMkData")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("org.example.mkdata.entities");
factoryBean.setPersistenceUnitName("mkdata");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE / FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
#Bean(name = "tmMkData")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
MkRadiusPersistence.class
#Configuration
#EnableTransactionManagement()
#EnableJpaRepositories(entityManagerFactoryRef = "emfMkRadius", transactionManagerRef = "tmMkRadius", basePackages = {"org.example.mkradius.repositories"})
#ConfigurationProperties(prefix = "databases.mkradius")
public class MkRadiusPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
#Bean(name = "dsMkRadius")
javax.sql.DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(10);
dataSource.setMaxActive(10);
return dataSource;
}
#Bean
HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
#Bean(name = "emfMkRadius")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("org.example.mkradius.entities");
factoryBean.setPersistenceUnitName("mkradius");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog); // SEVERE / FINEST
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
#Bean(name = "tmMkRadius")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
EDIT 2
Application.class
#Configuration
#ComponentScan(basePackages = { "org.example.startup" })
#EnableAutoConfiguration
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Autowired
CableRouteRepository cableRouteRepository;
#Autowired
CityRepository cityRepository;
#Autowired
RadAcctRepository radAcctRepository;
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.showBanner(false)
.sources(Application.class)
.run(args);
Application app = context.getBean(Application.class);
// for (String bean: context.getBeanDefinitionNames()) {
// logger.info(bean);
// }
app.start();
}
private void start() {
logger.info("Application.start()");
logger.info("{}", cableRouteRepository.findAll());
logger.info("{}", cityRepository.findAll());
logger.info("{}", radAcctRepository.findTest());
}
}
This is the starter class... I printed every repository as a test (each repository here is on a different DataSource)... They work fine as long as I don't have spring-starter-web on the classpath.
EDIT 3
Github Repo
https://github.com/mtrojahn/test-multiple-databases
I hope I did it right... I never really worked with Github :)
EDIT 4
Github updated properly with the failing code.
As a reminder if the dependency bellow is commented, the code works:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
And if the dependency above is uncommented but the code bellow is changed in the IntranetPersistence.class from:
#Primary
#Bean(name = "emfIntranet")
to
#Primary
#Bean(name = "entityManagerFactory")
It overwrites the default bean and starts to fail with:
Caused by: java.lang.IllegalArgumentException: Not an managed type: class org.example.intranet.entities.CableRoute
You're being affected by the behaviour of Spring Boot 1.2's JPA auto-configuration. It only switches off the creation of its own entityManagerFactory bean if there's a user-defined LocalContainerEntityManagerFactoryBean. You're using LocalContainerEntityManagerFactoryBean but calling afterPropertiesSet and getObject on it yourself rather than allowing the container to do so for you. This leaves the context will multiple #Primary EntityManagerFactory beans. This has been improved in Spring Boot 1.3 so that a user-declared EntityManagerFactory bean will also switch off the auto-configuration.
This causes a problem when trying to create openEntityManagerInViewInterceptor as it needs an EntityManagerFactory and the context has no way of knowing whic of the two #Primary beans it should choose.
There are a few ways to proceed. You could update your configuration to define beans that are of type LocalContainerEntityManagerFactoryBeans rather than EntityManagerFactory. Another is to disable the creation of the interceptor by adding the following to your application.yml:
spring:
jpa:
open_in_view: false

How to overload UserManager.AddToRoleAsync(string userId, string role)

I'm using Asp.net Identity Framework 2.1. I implement customized ApplicatoinUser, ApplicationRole, ApplicationUserRole, because I want to add support to multi-tenant, that is each user belongs to different companies, but I have 3 roles among all these companies, they are User, Admin and Approver.
My ApplicationUserRole derived from IdentityUserRole, and have one more property: CompanyId. This property will indicate the user's role in this particular company. My code for these customized classes attached in bottom.
My question is when I try to override ApplicationUserManager(Yes, it derived from UserManager too)'s AddToRoleAsync , IsInRoleAsync , I don't know how to deal with the new CompanyId, looks like the existing function doesn't receive these companyId(or tenantId).
Then when I'm trying to overload these functions with companyId included, I can't find the db context either in ApplicatoinUserManager nor its base class.
Am I on the right track of adding tenantId/companyId to the application Role?
I've referenced this answer: SO linkes, and this blog.ASP.NET Web Api and Identity 2.0 - Customizing Identity Models and Implementing Role-Based Authorization
My IdentityModels:
public class ApplicationUserLogin : IdentityUserLogin<string> { }
public class ApplicationUserClaim : IdentityUserClaim<string>
{
}
public class ApplicationUserRole : IdentityUserRole<string>
{
public string CompanyId { get; set; }
}
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>//, IAppUser
{
public ApplicationUser()
{
this.Id = Guid.NewGuid().ToString();
}
public virtual string CompanyId { get; set; }
public virtual List<CompanyEntity> Company { get; set; }
public DateTime CreatedOn { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
// Must be expressed in terms of our custom UserRole:
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole() {}
public ApplicationRole(string name) : this()
{
this.Name = name;
}
// Add any custom Role properties/code here
public string Description { get; set; }
}
// Most likely won't need to customize these either, but they were needed because we implemented
// custom versions of all the other types:
public class ApplicationUserStore: UserStore<ApplicationUser, ApplicationRole, string,ApplicationUserLogin, ApplicationUserRole,ApplicationUserClaim>, IUserStore<ApplicationUser, string>, IDisposable
{
public ApplicationUserStore()
: this(new IdentityDbContext())
{
base.DisposeContext = true;
}
public ApplicationUserStore(DbContext context)
: base(context)
{
}
}
public class ApplicationRoleStore
: RoleStore<ApplicationRole, string, ApplicationUserRole>,
IQueryableRoleStore<ApplicationRole, string>,
IRoleStore<ApplicationRole, string>, IDisposable
{
public ApplicationRoleStore()
: base(new IdentityDbContext())
{
base.DisposeContext = true;
}
public ApplicationRoleStore(DbContext context)
: base(context)
{
}
}
My IdentityConfig:
public class ApplicationUserManager
: UserManager<ApplicationUser, string>
{
public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
: base(store) { }
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(
new UserStore<ApplicationUser, ApplicationRole, string,
ApplicationUserLogin, ApplicationUserRole,
ApplicationUserClaim>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
//RequireNonLetterOrDigit = true,
//RequireDigit = true,
//RequireLowercase = true,
//RequireUppercase = true,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(
dataProtectionProvider.Create("ASP.NET Identity"));
}
// add sms and email service provider
manager.SmsService = new EMaySmsServiceProvider();
manager.EmailService = new ConcordyaEmailServiceProvider();
return manager;
}
public string GetCurrentCompanyId(string userName)
{
var user = this.FindByName(userName);
if (user == null)
return string.Empty;
var currentCompany = string.Empty;
if (user.Claims.Count > 0)
{
currentCompany = user.Claims.Where(c => c.ClaimType == ConcordyaPayee.Core.Common.ConcordyaClaimTypes.CurrentCompanyId).FirstOrDefault().ClaimValue;
}
else
{
currentCompany = user.CurrentCompanyId;
}
return currentCompany;
}
public override Task<IdentityResult> AddToRoleAsync(string userId, string role, string companyId)
{
return base.AddToRoleAsync(userId, role);
}
#region overrides for unit tests
public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return base.CheckPasswordAsync(user, password);
}
public override Task<ApplicationUser> FindByNameAsync(string userName)
{
return base.FindByNameAsync(userName);
}
#endregion
}
public class ApplicationRoleManager : RoleManager<ApplicationRole>
{
public ApplicationRoleManager(IRoleStore<ApplicationRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(
IdentityFactoryOptions<ApplicationRoleManager> options,
IOwinContext context)
{
return new ApplicationRoleManager(
new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
}
}
First of all, I would like to say thanks for taking it this far. It gave me a great start for my multi-tenant roles solution. I'm not sure if I'm 100% right, but this works for me.
Firstly, you cannot override any of the "RoleAsync" methods, but you can overload them. Secondly, the UserStore has a property called "Context" which can be set to your DbContext.
I had to overload the "RoleAsyc" methods in both my UserStore and UserManager extended classes. Here is an example from each to get you going:
MyUserStore
public class MyUserStore : UserStore<MyUser, MyRole, String, IdentityUserLogin, MyUserRole, IdentityUserClaim> {
public MyUserStore(MyDbContext dbContext) : base(dbContext) { }
public Task AddToRoleAsync(MyUser user, MyCompany company, String roleName) {
MyRole role = null;
try
{
role = Context.Set<MyRole>().Where(mr => mr.Name == roleName).Single();
}
catch (Exception ex)
{
throw ex;
}
Context.Set<MyUserRole>().Add(new MyUserRole {
Company = company,
RoleId = role.Id,
UserId = user.Id
});
return Context.SaveChangesAsync();
}
}
MyUserManager
public class MyUserManager : UserManager<MyUser, String>
{
private MyUserStore _store = null;
public MyUserManager(MyUserStore store) : base(store)
{
_store = store;
}
public Task<IList<String>> GetRolesAsync(String userId, int companyId)
{
MyUser user = _store.Context.Set<MyUser>().Find(new object[] { userId });
MyCompany company = _store.Context.Set<MyCompany>().Find(new object[] { companyId });
if (null == user)
{
throw new Exception("User not found");
}
if (null == company)
{
throw new Exception("Company not found");
}
return _store.GetRolesAsync(user, company);
}
}
From here a couple scary things happen and I don't know a better way to manage them.
The User "IsInRole" method in the HttpContext will work but it will not be tenant-sensitive so you can no longer use it.
If you use the "Authorize" attribute, the same idea for "scary thing 1" applies, but here you can just extend it and make things happy for your system. Example below:
MyAuthorizeAttribute
public class MyAuthorizeAttribute : AuthorizeAttribute {
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (null == httpContext)
{
throw new ArgumentNullException("httpContext");
}
HttpSessionStateBase session = httpContext.Session;
IList<String> authorizedRoleNames = Roles.Split(',').Select(r => r.Trim()).ToList();
if (!httpContext.User.Identity.IsAuthenticated)
{
return false;
}
if (null == session["MyAuthorize.CachedUsername"])
{
session["MyAuthorize.CachedUsername"] = String.Empty;
}
if (null == session["MyAuthorize.CachedCompanyId"])
{
session["MyAuthorize.CachedCompanyId"] = -1;
}
if (null == session["MyAuthorize.CachedUserCompanyRoleNames"])
{
session["MyAuthorize.CachedUserCompanyRoleNames"] = new List<String>();
}
String cachedUsername = session["MyAuthorize.CachedUsername"].ToString();
int cachedCompanyId = (int)session["MyAuthorize.CachedCompanyId"];
IList<String> cachedUserAllRoleNames = (IList<String>)session["MyAuthorize.CachedUserAllRoleNames"];
IPrincipal currentUser = httpContext.User;
String currentUserName = currentUser.Identity.Name;
int currentCompanyId = (int)session["CurrentCompanyId"];//Get this your own way! I used the Session in the HttpContext.
using (MyDbContext db = MyDbContext.Create())
{
try
{
MyUser mUser = null;
ICollection<String> tmpRoleIds = new List<String>();
if (cachedUsername != currentUserName)
{
session["MyAuthorize.CachedUsername"] = cachedUsername = String.Empty;
//Reload everything
mUser = db.Users.Where(u => u.Username == currentUserName).Single();
session["MyAuthorize.CachedUsername"] = currentUserName;
session["MyAuthorize.CachedCompanyId"] = cachedCompanyId = -1; //Force Company Reload
cachedUserCompanyRoleNames.Clear();
}
if (cachedUserCompanyRoleNames.Count != db.Users.Where(u => u.Username == currentUserName).Single().Roles.Select(r => r.RoleId).ToList().Count)
{
cachedUserCompanyRoleNames.Clear();
if (0 < currentCompanyId)
{
if(null == mUser)
{
mUser = db.Users.Where(u => u.Username == cachedUsername).Single();
}
tmpRoleIds = mUser.Roles.Where(r => r.Company.Id == currentCompanyId).Select(r => r.RoleId).ToList();
session["MyAuthorize.CachedUserCompanyRoleNames"] = cachedUserCompanyRoleNames = db.Roles.Where(r => tmpRoleIds.Contains(r.Id)).Select(r => r.Name).ToList();
session["MyAuthorize.CachedCompanyId"] = cachedCompanyId = currentCompanyId;
}
}
if (cachedCompanyId != currentCompanyId)
{
cachedUserCompanyRoleNames.Clear();
//Reload company roles
if (0 < currentCompanyId)
{
if(null == mUser)
{
mUser = db.Users.Where(u => u.Username == cachedUsername).Single();
}
tmpRoleIds = mUser.Roles.Where(r => r.Company.Id == currentCompanyId).Select(r => r.RoleId).ToList();
session["MyAuthorize.CachedUserCompanyRoleNames"] = cachedUserCompanyRoleNames = db.Roles.Where(r => tmpRoleIds.Contains(r.Id)).Select(r => r.Name).ToList();
session["MyAuthorize.CachedCompanyId"] = cachedCompanyId = currentCompanyId;
}
}
}
catch (Exception ex)
{
return false;
}
}
if (0 >= authorizedRoleNames.Count)
{
return true;
}
else
{
return cachedUserCompanyRoleNames.Intersect(authorizedRoleNames).Any();
}
}
}
In closing, as I said, I'm not sure if this is the best way to do it, but it works for me. Now, throughout your system, make sure you used your overloaded methods when dealing with Roles. I am also thinking about caching the Roles in a MVC BaseController that I wrote so that I can get similar functionality to User.IsInRole in all of my MVC Views.

Resources