Add JPA Key Provider

This commit is contained in:
Martin Stockhammer 2016-11-04 08:02:57 +01:00
parent 5420374314
commit 13aa63a4e5
10 changed files with 512 additions and 5 deletions

View File

@ -26,6 +26,7 @@
<class>org.apache.archiva.redback.rbac.jpa.model.JpaPermission</class> <class>org.apache.archiva.redback.rbac.jpa.model.JpaPermission</class>
<class>org.apache.archiva.redback.rbac.jpa.model.JpaRole</class> <class>org.apache.archiva.redback.rbac.jpa.model.JpaRole</class>
<class>org.apache.archiva.redback.rbac.jpa.model.JpaUserAssignment</class> <class>org.apache.archiva.redback.rbac.jpa.model.JpaUserAssignment</class>
<class>org.apache.archiva.redback.keys.jpa.model.JpaAuthenticationKey</class>
<properties> <properties>
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:redback_database"/> <property name="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:redback_database"/>
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/> <property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/>

View File

@ -27,6 +27,7 @@
<class>org.apache.archiva.redback.rbac.jpa.model.JpaPermission</class> <class>org.apache.archiva.redback.rbac.jpa.model.JpaPermission</class>
<class>org.apache.archiva.redback.rbac.jpa.model.JpaRole</class> <class>org.apache.archiva.redback.rbac.jpa.model.JpaRole</class>
<class>org.apache.archiva.redback.rbac.jpa.model.JpaUserAssignment</class> <class>org.apache.archiva.redback.rbac.jpa.model.JpaUserAssignment</class>
<class>org.apache.archiva.redback.keys.jpa.model.JpaAuthenticationKey</class>
<properties> <properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
<property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)" /> <property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)" />

View File

@ -31,5 +31,6 @@
<module>redback-keys-jdo</module> <module>redback-keys-jdo</module>
<module>redback-keys-memory</module> <module>redback-keys-memory</module>
<module>redback-keys-cached</module> <module>redback-keys-cached</module>
<module>redback-keys-jpa</module>
</modules> </modules>
</project> </project>

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>redback-keys-providers</artifactId>
<groupId>org.apache.archiva.redback</groupId>
<version>2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>redback-keys-jpa</artifactId>
<packaging>jar</packaging>
<name>Redback :: Key Management Provider :: JPA</name>
<dependencies>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-keys-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-common-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-keys-tests</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>${openjpa.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa-maven-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<includes>**/model/*.class</includes>
<addDefaultConstructor>true</addDefaultConstructor>
<enforcePropertyRestrictions>true</enforcePropertyRestrictions>
</configuration>
<executions>
<execution>
<id>enhancer</id>
<phase>process-classes</phase>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<!-- set the version to be the same as the level in your runtime -->
<version>${openjpa.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,156 @@
package org.apache.archiva.redback.keys.jpa;
import org.apache.archiva.redback.keys.AbstractKeyManager;
import org.apache.archiva.redback.keys.AuthenticationKey;
import org.apache.archiva.redback.keys.KeyManagerException;
import org.apache.archiva.redback.keys.KeyNotFoundException;
import org.apache.archiva.redback.keys.jpa.model.JpaAuthenticationKey;
import org.codehaus.plexus.util.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.*;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Created by martin on 27.10.16.
*/
@Service( "keyManager#jpa" )
public class JpaKeyManager extends AbstractKeyManager {
@PersistenceContext(unitName = "redback-jpa")
EntityManager em;
// JpaUserManager is a singleton and initialization should be thread safe
private AtomicBoolean initialized = new AtomicBoolean(false);
public void setEntityManager(EntityManager em) {
this.em = em;
}
private EntityManager getEm() {
if (initialized.compareAndSet(false,true)) {
Query q = em.createQuery("SELECT COUNT(u.key) FROM JpaAuthenticationKey u");
boolean dbInit = q.getFirstResult()==0;
}
return em;
}
public String getId()
{
return "JPA Key Manager - " + this.getClass().getName();
}
@Override
@Transactional
public AuthenticationKey createKey( String principal, String purpose, int expirationMinutes )
throws KeyManagerException
{
JpaAuthenticationKey authkey = new JpaAuthenticationKey();
authkey.setKey( super.generateUUID() );
authkey.setForPrincipal( principal );
authkey.setPurpose( purpose );
Calendar now = getNowGMT();
authkey.setDateCreated( now.getTime() );
if ( expirationMinutes >= 0 )
{
Calendar expiration = getNowGMT();
expiration.add( Calendar.MINUTE, expirationMinutes );
authkey.setDateExpires( expiration.getTime() );
}
return addKey( authkey );
}
@Transactional
@Override
public AuthenticationKey addKey(AuthenticationKey key) {
final EntityManager em = getEm();
AuthenticationKey mergedKey = em.merge((JpaAuthenticationKey)key);
return mergedKey;
}
@Transactional
@Override
public void eraseDatabase()
{
final EntityManager em = getEm();
Query q = em.createQuery("DELETE FROM JpaAuthenticationKey k");
q.executeUpdate();
}
@Transactional
@Override
public AuthenticationKey findKey(final String key) throws KeyNotFoundException, KeyManagerException {
final EntityManager em = getEm();
if ( StringUtils.isEmpty( key ) )
{
throw new KeyNotFoundException( "Empty key not found." );
}
try
{
TypedQuery<JpaAuthenticationKey> q =
em.createQuery("SELECT k FROM JpaAuthenticationKey k WHERE k.key = :key",JpaAuthenticationKey.class);
q.setParameter("key",key);
JpaAuthenticationKey authkey = q.getSingleResult();
if ( authkey == null )
{
throw new KeyNotFoundException( "Key [" + key + "] not found." );
}
assertNotExpired( authkey );
return authkey;
} catch (NoResultException ex) {
throw new KeyNotFoundException("Key [" + key + "] not found.");
} catch (KeyNotFoundException ex) {
throw ex;
} catch (Throwable ex) {
log.error("Error while trying to retrieve JpaAuthenticationKey {}", key);
throw new KeyManagerException("Error while retrieving key "+key+": "+ex.getMessage(), ex);
}
}
@Transactional
@Override
protected void assertNotExpired(AuthenticationKey authkey) throws KeyManagerException {
super.assertNotExpired(authkey);
}
@Transactional
@Override
public void deleteKey(AuthenticationKey key) throws KeyManagerException {
final EntityManager em = getEm();
em.remove((JpaAuthenticationKey)key);
}
@Transactional
@Override
public void deleteKey(String key) throws KeyManagerException {
try {
JpaAuthenticationKey foundKey = (JpaAuthenticationKey)findKey(key);
em.remove(foundKey);
} catch (KeyNotFoundException ex) {
// Ignore
} catch (Exception ex) {
log.error("Error occured while trying to find key {}: {}", key, ex.getMessage());
throw new KeyManagerException("Error while retrieving key "+key, ex);
}
}
@Override
public List<AuthenticationKey> getAllKeys() {
final EntityManager em = getEm();
Query q= em.createQuery("SELECT x from JpaAuthenticationKey x");
return q.getResultList();
}
}

View File

@ -0,0 +1,88 @@
package org.apache.archiva.redback.keys.jpa.model;
import org.apache.archiva.redback.keys.AuthenticationKey;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* Created by martin on 27.10.16.
*/
@javax.persistence.Entity
@Table(name="JDOAUTHENTICATIONKEY")
public class JpaAuthenticationKey implements AuthenticationKey {
@Column(name="AUTHKEY")
@Id
private String key;
@Column(name="FOR_PRINCIPAL")
private String forPrincipal;
@Column(name="PURPOSE")
private String purpose;
@Column(name="DATE_CREATED")
private Date dateCreated;
@Column(name="DATE_EXPIRES")
private Date dateExpires;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getForPrincipal() {
return forPrincipal;
}
public void setForPrincipal(String forPrincipal) {
this.forPrincipal = forPrincipal;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Date getDateExpires() {
return dateExpires;
}
public void setDateExpires(Date dateExpires) {
this.dateExpires = dateExpires;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JpaAuthenticationKey that = (JpaAuthenticationKey) o;
return key.equals(that.key);
}
@Override
public int hashCode() {
return key.hashCode();
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config />
<context:component-scan base-package="org.apache.archiva.redback.keys.jpa" />
</beans>

View File

@ -0,0 +1,65 @@
package org.apache.archiva.redback.keys.jpa;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.redback.keys.KeyManager;
import org.apache.archiva.redback.keys.KeyManagerTestCase;
import org.junit.Before;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManagerFactory;
/**
* JdoKeyManagerTest
*
* @author <a href="mailto:martin_s@apache.org">Martin Stockhammer</a>
*
*/
@Transactional
public class JpaKeyManagerTest
extends KeyManagerTestCase
{
@Inject
EntityManagerFactory entityManagerFactory;
@Inject
@Named(value = "keyManager#jpa")
KeyManager keyManager;
@Before
public void setUp()
throws Exception {
super.setUp();
super.setKeyManager(keyManager);
}
@Test
public void initialize() {
assertNotNull(keyManager);
}
}

View File

@ -0,0 +1,61 @@
<?xml version="1.0"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="org.apache.archiva.redback.keys.jpa" />
<bean name="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter" >
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter" />
</property>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence-hsqldb.xml" />
<property name="jpaPropertyMap">
<map>
<entry key="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:redback_database" />
<entry key="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver" />
<entry key="openjpa.ConnectionUserName" value="sa" />
<entry key="openjpa.ConnectionPassword" value="" />
<entry key="openjpa.Log" value="DefaultLevel=TRACE, Runtime=TRACE, Tool=INFO, SQL=TRACE" />
<entry key="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
<entry key="openjpa.jdbc.MappingDefaults"
value="ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict"/>
</map>
</property>
</bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
</beans>

View File

@ -23,10 +23,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collections; import java.util.*;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
/** /**
* KeyManagerTestCase * KeyManagerTestCase
@ -115,11 +112,14 @@ public class KeyManagerTestCase
assertEquals( "bar", created2.getForPrincipal() ); assertEquals( "bar", created2.getForPrincipal() );
assertEquals( "Something", created2.getPurpose() ); assertEquals( "Something", created2.getPurpose() );
List<AuthenticationKey> keys = getKeyManager().getAllKeys(); System.out.println("foo key "+created1.getKey());
System.out.println("bar key "+created2.getKey());
List<AuthenticationKey> keys = new ArrayList(getKeyManager().getAllKeys());
Collections.sort( keys, new Comparator<AuthenticationKey>() Collections.sort( keys, new Comparator<AuthenticationKey>()
{ {
public int compare( AuthenticationKey key1, AuthenticationKey key2 ) public int compare( AuthenticationKey key1, AuthenticationKey key2 )
{ {
System.out.println("Compare "+key2.getForPrincipal()+key2.getKey()+" - "+key1.getForPrincipal()+key1.getKey());
return key2.getForPrincipal().compareTo( key1.getForPrincipal() ); return key2.getForPrincipal().compareTo( key1.getForPrincipal() );
} }
} ); } );