I have the following POCO class:
public class Person : Entity
{
public string FirstName { get; set; }
public string MiddleName1 { get; set; }
public string MiddleName2 { get; set; }
public string LastName { get; set; }
public byte? DayOfBirth { get; set; }
public byte? MonthOfBirth { get; set; }
public Int16? YearOfBirth { get; set; }
public string MobileNumber { get; set; }
}
public abstract class Entity
{
public int Id { get; set; }
}
Here is the corresponding edmx xml:
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
<edmx:StorageModels>
<Schema Namespace="EntityFramework.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
<EntityContainer Name="EntityFrameworkStoreContainer">
<EntitySet Name="People" EntityType="EntityFramework.Store.People" store:Type="Tables" Schema="dbo" />
</EntityContainer>
<EntityType Name="People">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" Nullable="false" />
<Property Name="FirstName" Type="nvarchar" Nullable="false" MaxLength="50" />
<Property Name="MiddleName1" Type="nvarchar" MaxLength="50" />
<Property Name="MiddleName2" Type="nvarchar" MaxLength="50" />
<Property Name="LastName" Type="nvarchar" Nullable="false" MaxLength="50" />
<Property Name="DayOfBirth" Type="tinyint" />
<Property Name="MonthOfBirth" Type="tinyint" />
<Property Name="YearOfBirth" Type="smallint" />
<Property Name="MobileNumber" Type="varchar" MaxLength="20" />
</EntityType>
</Schema>
</edmx:StorageModels>
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema Namespace="EntityFramework" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
<EntityContainer Name="TheCleavesEntities" annotation:LazyLoadingEnabled="true">
<EntitySet Name="People" EntityType="EntityFramework.Person" />
</EntityContainer>
<EntityType Name="Person">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Int32" Nullable="false" />
<Property Name="FirstName" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="MiddleName1" Type="String" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="MiddleName2" Type="String" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="LastName" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="DayOfBirth" Type="Byte" Nullable="true" />
<Property Name="MonthOfBirth" Type="Byte" Nullable="true" />
<Property Name="YearOfBirth" Type="Int16" Nullable="true" />
<Property Name="MobileNumber" Type="String" MaxLength="20" Unicode="false" FixedLength="false" />
</EntityType>
</Schema>
</edmx:ConceptualModels>
<!-- C-S mapping content -->
<edmx:Mappings>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs">
<EntityContainerMapping StorageEntityContainer="EntityFrameworkStoreContainer" CdmEntityContainer="TheCleavesEntities">
<EntitySetMapping Name="People"><EntityTypeMapping TypeName="EntityFramework.Person"><MappingFragment StoreEntitySet="People">
<ScalarProperty Name="Id" ColumnName="Id" />
<ScalarProperty Name="FirstName" ColumnName="FirstName" />
<ScalarProperty Name="MiddleName1" ColumnName="MiddleName1" />
<ScalarProperty Name="MiddleName2" ColumnName="MiddleName2" />
<ScalarProperty Name="LastName" ColumnName="LastName" />
<ScalarProperty Name="DayOfBirth" ColumnName="DayOfBirth" />
<ScalarProperty Name="MonthOfBirth" ColumnName="MonthOfBirth" />
<ScalarProperty Name="YearOfBirth" ColumnName="YearOfBirth" />
<ScalarProperty Name="MobileNumber" ColumnName="MobileNumber" />
</MappingFragment></EntityTypeMapping></EntitySetMapping>
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
</edmx:Runtime>
<!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
<Designer xmlns="http://schemas.microsoft.com/ado/2008/10/edmx">
<Connection>
<DesignerInfoPropertySet>
<DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
</DesignerInfoPropertySet>
</Connection>
<Options>
<DesignerInfoPropertySet>
<DesignerProperty Name="ValidateOnBuild" Value="true" />
<DesignerProperty Name="EnablePluralization" Value="True" />
<DesignerProperty Name="IncludeForeignKeysInModel" Value="False" />
</DesignerInfoPropertySet>
</Options>
<!-- Diagram content (shape and connector positions) -->
<Diagrams>
<Diagram Name="TheCleaves">
<EntityTypeShape EntityType="EntityFramework.Person" Width="1.5" PointX="0.75" PointY="0.75" Height="2.7494921874999996" IsExpanded="true" />
</Diagram>
</Diagrams>
</Designer>
</edmx:Edmx>
When I load up an entity (there's only one row in the database at present) with the code:
IEnumerable<Person> people = context.People.Where(x => true);
I'm finding that the Id property of the returned Person object is 0 (it's 1 in the database). Anyone have any idea why it appears not to be set?
Thanks
Ok it is not problem with inheritance as I initially thought - the inheritance will work. This is most probably combination of two problems:
Id is generated in the database but EF doesn't know about them. Both SSDL and CSDL part of EDMX should define Id with StoreGeneratedPattern.Identity. This will force EF to reload Id when entity is inserted.
I believe you are using same context instance for saving entity and calling the query. Now you meet identity map pattern. Despite the data retrieved from the query EF will use instance internally stored in its per-context cache. Because of the first problem the cached instance has Id with default int value = 0.
Related
AuthenticationProvider function authenticate not call after migration spring security 2 to spring security 4.
I am use custom provider and ldap authentication, all of my config its ok , but when I try to connect , I have an anonymousUser in my AccessDecisionVoter.vote
please see the description code here:
public class RoleVoter implements AccessDecisionVoter<Object> {
#SuppressWarnings("unchecked")
public boolean supports(Class clazz) {
return true;
}
/**
* #see AccessDecisionVoter#supports(ConfigAttribute)
*/
public boolean supports(ConfigAttribute configAttribute) {
if (getAttributeValue(configAttribute) != null) {
try {
//Integer.parseInt(configAttribute.getAttribute());
return true;
} catch (Exception e) {
return false;
}
}
return false;
}
public String getAttributeValue(ConfigAttribute attribute){
if (attribute instanceof ConfigAttribute) {
return attribute.toString();
}
return attribute.getAttribute();
}
public int vote(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributeDefinition) {
return result;
}
}
#Component
public class MyAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOG = Logger
.getLogger(MyAuthenticationProvider.class);
protected MessageSourceAccessor messages = SpringSecurityMessageSource
.getAccessor();
private LdapAuthenticator authenticator;
private UserDetailsService userDetailsService;
private boolean useAuthenticationRequestCredentials = true;
public MyAuthenticationProvider(LdapAuthenticator authenticator,
UserDetailsService userDetailsService) {
setAuthenticator(authenticator);
setUserDetailsService(userDetailsService);
}
public MyAuthenticationProvider() {
}
//—> not called????
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class,authentication,messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.onlySupports",
"Only UsernamePasswordAuthenticationToken is supported"));
UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication;
//my authentication
return return new UsernamePasswordAuthenticationToken(user, password, user
.getAuthorities());
}
private LdapAuthenticator getAuthenticator() {
return authenticator;
}
protected UserDetailsService getUserDetailsService() {
return userDetailsService;
}
private void setAuthenticator(LdapAuthenticator authenticator) {
Assert.notNull(authenticator, "An LdapAuthenticator must be supplied");
this.authenticator = authenticator;
}
private void setUserDetailsService(UserDetailsService userDetailsService) {
Assert.notNull(userDetailsService,
"An UserDetailsService must be supplied");
this.userDetailsService = userDetailsService;
}
#SuppressWarnings("unchecked")
#Override
public boolean supports(Class authentication) {
return UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<!-- Security configuration -->
<security:http pattern="/struts/**" security="none" />
<security:http pattern="/resources/**" security="none" />
<security:http pattern="/dojo/**" security="none" />
<security:http pattern="/index.jsp" security="none" />
<security:http pattern="/pages/authentication/auth.jsp*"
security="none" />
<security:http pattern="/authentication/authErr.action*"
security="none" />
<security:http pattern="/authentication/auth.action*"
security="none" />
<security:http pattern="/authentication/logout.action*"
security="none" />
<security:http pattern="/resources/firefox/*" security="none" />
<!-- ************************************************************************** -->
<security:http disable-url-rewriting="false" auto-config="true" use-expressions="false" access-decision-manager-ref="myAccessDecisionManager">
<security:access-denied-handler error-page="/pages/authentication/denied.jsp"/>
<security:csrf disabled="true"/>
<security:headers disabled="true"/>
<security:intercept-url pattern="/struts/**" />
<security:intercept-url pattern="/resources/**" />
<security:intercept-url pattern="/dojo/**" />
<security:intercept-url pattern="/index.jsp" />
<security:intercept-url
pattern="/pages/authentication/auth.jsp*" />
<security:intercept-url
pattern="/authentication/authErr.action*" />
<security:intercept-url
pattern="/authentication/auth.action*" />
<security:intercept-url pattern="/authentication/logout.action*" />
<security:intercept-url pattern="/resources/firefox/*" />
<security:intercept-url pattern="/**" access="hasRole('1')" /><!-- OR access=1 -->
<security:form-login
login-page="/authentication/auth.action"
always-use-default-target="false"
default-target-url="/home/home.action"
authentication-failure-url="/authentication/authErr.action" />
<security:anonymous granted-authority="99" />
<security:session-management>
<security:concurrency-control error-if-maximum-exceeded="true" max-sessions="1"/>
</security:session-management>
</security:http>
<!-- LDAP configuration -->
<bean id="dbLdapManager"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="local.framework.ldap-java5.DBLdapManager" />
<property name="targetMethod" value="setDbLdapParameters" />
<property name="arguments">
<list>
<bean id="dbLdapParameters"
class="local.framework.ldap-java5.DBLdapParameters">
<property name="application" value="refpat" />
<property name="dbLdapDriver"
value="com.sun.jndi.ldap.LdapCtxFactory" />
<property name="dbLdapURL"
value="${ldap-host}" />
</bean>
</list>
</property>
</bean>
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="${ldap-host}" />
<property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
<property name="pooled" value="true" />
</bean>
<bean id="ldapAuthProvider"
class="mypackage.security.provider.MyAuthenticationProvider">
<!-- <security:custom-authentication-provider /> -->
<constructor-arg>
<bean
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userDnPatterns">
<list>
<value>${ldap-dn-pattern}</value>
</list>
</property>
</bean>
</constructor-arg>
<constructor-arg ref="userService" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapAuthProvider"/>
</security:authentication-manager>
<bean id="userService"
class="mypackage.security.MyUserDetails">
<property name="serviceLookups" ref="serviceLookups" />
</bean>
<bean id="myAccessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"><!-- old:org.springframework.security.vote.UnanimousBased -->
<constructor-arg>
<list>
<bean class="mypackage.security.vote.RoleVoter"/>
<!-- other voter …—>
</list>
</constructor-arg>
</bean>
<bean id="loggerListener"
class="org.springframework.security.access.event.LoggerListener" />
</beans>
any solution/idea to solve my probleme ? thank a lot
I have implemented spring security oauth2 in my server for authentication.Now i have to implement a exception handler which will be called when a REST request with wrong credentials,expired token,etc. comes and which will respond with json string as error message instead of throwing exception.How can i set a exception handler in spring security oauth2.Does it have a default error handler,if how to set that in configuration file?
Below is my code.
spring-security.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd ">
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="authenticationManager"
xmlns="http://www.springframework.org/schema/security" >
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" method="POST" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<http pattern="/protected/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/protected/**" method="GET" access="ROLE_APP" />
<!-- <intercept-url pattern="/resources/**" access="IS_AUTHENTICATED_FULLY" /> -->
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<http pattern="/logout" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/logout" method="GET" />
<sec:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="logoutSuccessHandler" class="com.example.myproject.security.LogoutImpl" >
<property name="tokenstore" ref="tokenStore"></property>
</bean>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="exceptionTranslator" ref="myExceptionTranslator"></property>
</bean>
<bean id="myExceptionTranslator"
class="org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator">
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
</bean>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="clientDetails" class="com.example.myproject.service.ClientService"/>
<authentication-manager id="userAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="userService">
</authentication-provider>
</authentication-manager>
<bean id="userService"
class="com.example.myproject.service.UserService">
</bean>
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:authorization-code />
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials />
<oauth:password authentication-manager-ref="userAuthenticationManager"/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="springsec" token-services-ref="tokenServices" />
<!-- <bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" /> -->
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" >
<property name="authenticationKeyGenerator">
<bean class="com.example.myproject.service.UniqueAuthenticationKeyGenerator" />
</property>
</bean>
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="300000"></property>
<property name="clientDetailsService" ref="clientDetails" />
<property name="tokenEnhancer"><bean class="com.example.myproject.service.CustomTokenEnhancer" /></property>
</bean>
<sec:global-method-security
pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the
http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
</beans>
ClientService.java :
#Component
public class ClientService implements ClientDetailsService {
#Autowired
private OauthRepository oauthRepository;
#Override
public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException{
BaseClientDetails clientDetails = oauthRepository.getByClientId(s);
return clientDetails;
}
}
UserService.java :
#Component
public class UserService implements UserDetailsService {
#Autowired
private OauthRepository oauthRepository;
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserDetails user = oauthRepository.getByUsername(s);
return user;
}
}
OauthRepository.java :
#Repository
#Transactional
public class OauthRepository {
#Autowired
private SessionFactory sessionFactory;
#Autowired
private InMemoryTokenStore tokenStore;
private org.hibernate.Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
public UserDetails getByUsername(String username) {
MyUser user=new MyUser();
user.setUserName(username);
Query query=getCurrentSession().createQuery("FROM User WHERE userName=:usrName");
query.setParameter("usrName", username);
List<SiUser> getUser=query.list();
User act=getUser.get(0);
user.setPassword(act.getPassword());
user.setUserId(act.getUserId());
user.setAuthorities(getAuthorities(act.getUserId()));
return user;
}
public BaseClientDetails getByClientId(String clientId) {
System.out.println(" *** OauthRepository.getByClientId "+clientId);
Query query=getCurrentSession().createQuery("FROM OauthClientDetails WHERE clientId=:clientId");
query.setParameter("clientId", clientId);
List<OauthClientDetails> getClient=query.list();
OauthClientDetails oauthClient=getClient.get(0);
BaseClientDetails details = new BaseClientDetails();
details.setClientId(oauthClient.getClientId());
List<String> grantTypesList = Arrays.asList(oauthClient.getAuthorizedGrantTypes().split(","));
details.setAuthorizedGrantTypes(grantTypesList);
details.setClientSecret(oauthClient.getClientSecret());
return details;
}
/**
* Retrieves a collection of {#link GrantedAuthority} based on a numerical role
* #param role the numerical role
* #return a collection of {#link GrantedAuthority
*/
public Collection<GrantedAuthority> getAuthorities(Integer role) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
return authList;
}
/**
* Converts a numerical role to an equivalent list of roles
* #param role the numerical role
* #return list of roles as as a list of {#link String}
*/
public List<String> getRoles(Integer role) {
List<String> roles = new ArrayList<String>();
Query query=getCurrentSession().createQuery("FROM UserRole WHERE userID=:userId");
query.setParameter("userId", role);
List<SiUserRole> getUser=query.list();
UserRole actRole=getUser.get(0);
roles.add(actRole.getRole());
return roles;
}
/**
* Wraps {#link String} roles to {#link SimpleGrantedAuthority} objects
* #param roles {#link String} of roles
* #return list of granted authorities
*/
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new GrantedAuthorityImpl(role));
}
return authorities;
}
}
servlet-context.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!-- #author Nagesh.Chauhan(neel4soft#gmail.com) -->
<context:annotation-config />
<context:component-scan base-package="com.example.myproject" />
<mvc:annotation-driven />
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="1000000000" />
</bean>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/MyDatabase"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<!-- Hibernate Session Factory -->
<bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan">
<array>
<value>com.example.myproject</value>
</array>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</value>
</property>
</bean>
<!-- Hibernate Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<!-- Activates annotation based transaction management -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
I'm using Spring Security 3 with LDAP authenticated in my Spring MVC project.
It works fine until I need to deploy my project to other environment and change JDK's version from 1.6 to 1.7.
below is my spring security config file and sample code:
1) security-application-Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:s="http://www.springframework.org/schema/security"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<s:http use-expressions="true">
<s:intercept-url pattern="/auth/**" access="permitAll" />
<s:intercept-url pattern="/css/**" access="permitAll" />
<s:intercept-url pattern="/image/**" access="permitAll" />
<s:intercept-url pattern="/scripts/**" access="permitAll" />
<s:intercept-url pattern="/**" access="hasRole('GENERAL_USER')" />
<s:form-login login-page="/auth/login.html"
default-target-url="/welcome.html"
authentication-failure-url="/auth/login.html?error=1" />
<s:access-denied-handler error-page="/auth/denied.html"/>
<s:logout invalidate-session="true" logout-success-url="/auth/logoutSuccess.html"/>
</s:http>
<s:authentication-manager>
<s:authentication-provider ref="ldapAuthProvider" />
</s:authentication-manager>
<bean
id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"
scope="singleton">
<constructor-arg
value="ldap://ldapurl:389/dc=o,dc=a" />
<property name="userDn" value="cn=xxx,cn=users,dc=o,dc=a" />
<property name="password" value="password" />
<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.referral">
<value>follow</value>
</entry>
</map>
</property>
</bean>
<bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<!-- searchBase, searchFilter, contextSource -->
<constructor-arg index="0" value="" />
<constructor-arg index="1" value="(sAMAccountName={0})" />
<constructor-arg index="2" ref="contextSource" />
</bean>
<bean id="ldapAuthProvider"
class="com.foo.auth.MyLdapAuthenticationProvider">
<constructor-arg>
<bean
class="com.foo.auth.MyLdapAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userSearch">
<ref bean="userSearch" />
</property>
</bean>
</constructor-arg>
<property name="authoritiesPopulator" ref="authoritiesPopulator" />
<property name="userDetailsContextMapper" ref="userDetailsMapper" />
</bean>
<bean id="authoritiesPopulator" class="com.foo.auth.MyLdapAuthoritiesPopulator">
<constructor-arg ref="userService" />
</bean>
<bean id="userService" class="com.foo.auth.MyLdapUserDetailsService">
<constructor-arg ref="userSearch" />
<property name="userDetailsMapper" ref="userDetailsMapper" />
</bean>
<bean id="userDetailsMapper" class="com.foo.auth.MyUserDetailsContextMapper">
</bean>
</beans>
2) after success logon will redirect the url to welcome.jsp, in welcome.jsp, I use spring security taglib to get logon user's full name. (for test, I use principal to show whole context info):
<security:authentication property="principal"></security:authentication>
when use JDK 1.6, principal shows:
com.foo.auth.MyUserDetails#3e2d20ec:.........
and I can use my custom UserDetail's attribute such like principal.fullName.
when use JDK 1.7, principal shows:
org.springframework.security.ldap.userdetails.LdapUserDetailsImpl#86dae957:...
it doesn't get my custom UserDetail object. so if I use JDKk1.7, I can't get Spring context correctly.
this issue takes me almost 1 week to found out the root cause is JDK version's problem ;-(
does anyone know why spring security with LDAP doesn't work in JDK1.7? or I miss something to config?
thank you in advance!
Problem fixed.
It is because my MyLdapAuthenticationProvider extends wrong provider.
I change MyLdapAuthenticationProvider extended class to LdapAuthenticationProvider,
and the spring security is work fine both in JDK 1.6 and 1.7 now.
Here is my custom LdapAuthenticationProvider:
public class MyLdapAuthenticationProvider extends LdapAuthenticationProvider {
private static Logger logger = Logger.getLogger(MyLdapAuthenticationProvider.class);
private MyLdapAuthenticator authenticator;
#Autowired
private MyLdapAuthoritiesPopulator authoritiesPopulator;
#Autowired
private MyUserDetailsContextMapper userDetailsContextMapper;
public MyLdapAuthenticationProvider(LdapAuthenticator authenticator) {
super(authenticator);
this.authenticator = (MyLdapAuthenticator) authenticator;
}
#Override
protected DirContextOperations doAuthentication(UsernamePasswordAuthenticationToken userToken) {
try {
DirContextOperations dirCtx = getAuthenticator().authenticate(userToken);
return dirCtx;
} catch (PasswordPolicyException ppe) {
throw new LockedException(this.messages.getMessage(ppe.getStatus().getErrorCode(), ppe.getStatus()
.getDefaultMessage()));
} catch (UsernameNotFoundException notFound) {
throw new BadCredentialsException("User Name Error!");
} catch (NamingException ldapAccessFailure) {
throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
}
}
private void setAuthenticator(MyLdapAuthenticator authenticator) {
Assert.notNull(authenticator, "An LdapAuthenticator must be supplied");
this.authenticator = authenticator;
}
private MyLdapAuthenticator getAuthenticator() {
return authenticator;
}
public MyUserDetailsContextMapper getUserDetailsContextMapper() {
return userDetailsContextMapper;
}
public void setUserDetailsContextMapper(MyUserDetailsContextMapper userDetailsContextMapper) {
this.userDetailsContextMapper = userDetailsContextMapper;
}
public void setAuthoritiesPopulator(MyLdapAuthoritiesPopulator authoritiesPopulator) {
this.authoritiesPopulator = authoritiesPopulator;
}
public MyLdapAuthoritiesPopulator getAuthoritiesPopulator() {
return authoritiesPopulator;
}
}
I have the following models:
WeatherForecast:
namespace TravelAssistant.Model.HelperModels.Weather
public class WeatherForecast:EntityBase<int>
{
public IList<DayForecast> ForecastDays { get; set; }
public LocationBase ForecastLocation { get; set; }
public void Init(Location.LocationBase location)
{
this.ForecastLocation = location;
}
protected override void Validate()
{
throw new NotImplementedException();
}
}
LocationBase:
namespace TravelAssistant.Model.HelperModels.Location
public class LocationBase:EntityBase<int>
{
public string WorldRegion { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Zipcode { get; set; }
public string StreetNameNumber { get; set; }
}
where EntityBase defines an id of type T, and the following .hbm files
WeatherForecast.hbm.xml:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="TravelAssistant.Model.HelperModels.Weather"
assembly="TravelAssistant.Model">
<class name="WeatherForecast" table="WeatherForecasts" lazy="false" >
<id name="Id" column="WeatherForecastID"
type="int" unsaved-value="0">
<generator class="native" />
</id>
<many-to-one name="ForecastLocation"
cascade="all"
class="LocationBase"
column="LocationID"
not-null="false" />
<bag name="ForecastDays" lazy="false" >
<key column="WeatherForecastID"/>
<one-to-many class="DayForecast"></one-to-many>
</bag>
</class>
</hibernate-mapping>
LocationBase.hbm.xml
<id name="Id" column="LocationID" type="int" unsaved-value="0">
<generator class="native" />
</id>
<property name="City">
<column name="City"
sql-type="varchar(150)" not-null="true" />
</property>
<property name="Country">
<column name="Country"
sql-type="varchar(50)" not-null="true" />
</property>
<property name="Zipcode">
<column name="Zipcode"
sql-type="varchar(50)" not-null="false" />
</property>
<property name="StreetNameNumber">
<column name="StreetNameNumber"
sql-type="varchar(150)" not-null="false" />
</property>
<property name="WorldRegion">
<column name="WorldRegion"
sql-type="varchar(100)" not-null="false" />
</property>
</class>
</hibernate-mapping>
The database model is:
WeatherForecasts : WeatherForecastID, LocationID
Locations:LocationID,City,Country,Zipcode, StreetNameNumber,WorldRegion.
When I run the program I get:
An association from the table WeatherForecasts refers to an unmapped class:
TravelAssistant.Model.HelperModels.Weather.LocationBase
Can someone point me where I got it wrong?
Try using the fully qualified class name for the many-to-one association on the WeatherForecast mapping.
<many-to-one
name="ForecastLocation"
cascade="all"
class="TravelAssistant.Model.HelperModels.Location.LocationBase, TravelAssistant.Model"
column="LocationID"
not-null="false" />
I would like to include the value of a scalar function as a read-only property of an entity, since that I could include that value in a filter, is such a thing possible?
The solution is to add a DefiningQuery like in the following sample:
<!-- SSDL content -->
<EntitySet Name="Emp" EntityType="TestModel.Store.Emp" >
<DefiningQuery>
SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO, dbo.MyFunc(DEPTNO) AS DNAME FROM EMP
</DefiningQuery>
</EntitySet>
<EntityType Name="Emp">
<Key>
<PropertyRef Name="EMPNO" />
</Key>
<Property Name="EMPNO" Type="int" Nullable="false" />
...
<Property Name="DNAME" Type="varchar" MaxLength ="20" />
</EntityType>
...
<!-- CSDL content -->
...
<EntityType Name="Emp">
<Key>
<PropertyRef Name="EMPNO" />
</Key>
<Property Name="EMPNO" Type="Int32" Nullable="false" />
...
<Property Name="DNAME" Type="String" MaxLength="20" Unicode="false" FixedLength="false" />
</EntityType>
<!-- C-S mapping content -->
...
<ScalarProperty Name="EMPNO" ColumnName="EMPNO" />
...
<ScalarProperty Name="DNAME" ColumnName="DNAME" />
...
The usage example:
using(TestEntities4 db = new TestEntities4()) {
var q = from e in db.Emp where e.DNAME == "RESEARCH" select e;
}
In EF4 you can define a partial class of the same name as your Entity Framework class in the same namespace and add read-only properties to that. I've just done that to expose the description of a connected Entity object as a read-only property of the original object.
namespace same.as.the.data.model
{
public partial class Order
{
public string CustomerName
{
get { return Customer.Name; }
}
}
}