Grails 2.5.6 and SAML 2.0 - grails-2.0

I use Grails 2.5.6 and I try to config saml with the plugin.
I can call the saml login but after my login I get a blanc site with redirect loop.
BuildConfig:
dependencies{
/*...*/
compile('org.springframework.security.extensions:spring-security-saml2-core:1.0.2.RELEASE'){
export = false
}
compile('org.springframework.security:spring-security-core:3.2.9.RELEASE')
compile('org.springframework.security:spring-security-web:3.2.9.RELEASE')
}
plugins{
/*...*/
compile ":spring-security-core:2.0.0"
compile ":spring-security-saml:2.0.0"
}
Config:
grails.plugin.springsecurity.userLookup.userDomainClassName = "de.streit.user.User"
grails.plugin.springsecurity.userLookup.authorityJoinClassName = "de.streit.security.UserRole"
grails.plugin.springsecurity.authority.className = "de.streit.security.Role"
grails.plugin.springsecurity.requestMap.className = 'de.streit.security.Requestmap'
grails.plugin.springsecurity.securityConfigType = 'Requestmap'
grails.plugin.springsecurity.authenticationFailureUrl = '/login/authfail?login_error=1'
// Define the authentication providers
grails.plugin.springsecurity.providerNames = ["samlAuthenticationProvider"]
grails.plugin.springsecurity.useSwitchUserFilter = true
//SAML
grails.plugin.springsecurity.saml.active = true
grails.plugin.springsecurity.saml.metadata.providers = [idp: 'security/idp.xml']
grails.plugin.springsecurity.saml.metadata.defaultIdp = 'idp'
grails.plugin.springsecurity.saml.metadata.sp.defaults = [
signingKey: 'estar',
encryptionKey: 'estar',
tlsKey: 'estar',
alias : 'http://localhost:8080/Organisationsportal'
]
SP.XML:
<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor entityID="http://localhost:8080/Organisationsportal" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:Extensions>
<idpdisco:DiscoveryResponse xmlns:idpdisco="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol"
Location="http://localhost:8080/Organisationsportal/spring-security-saml/login/auth"/>
</md:Extensions>
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
MIIC9jCCArSgAwIBAgIETo67pDALBgcqhkjOOAQDBQAwXjELMAkGA1UEBhMCVUsxEDAOBgNVBAgT
B1Vua25vd24xDzANBgNVBAcTBmxvbmRvbjENMAsGA1UEChMEYnVyYjENMAsGA1UECxMEYnVyYjEO
MAwGA1UEAxMFZmVyb3owHhcNMTExMDA3MDg0MzE2WhcNMTIwMTA1MDg0MzE2WjBeMQswCQYDVQQG
EwJVSzEQMA4GA1UECBMHVW5rbm93bjEPMA0GA1UEBxMGbG9uZG9uMQ0wCwYDVQQKEwRidXJiMQ0w
CwYDVQQLEwRidXJiMQ4wDAYDVQQDEwVmZXJvejCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB
HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/y
ZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq
7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7
+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4r
s6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKB
gQDKBDz1DFPPmmWp9n1FskJOev7CnnVFsKji1NLUDdifvS+uW+cnvnDfD3yPdxzUeknCrPTBRp+B
IvYUvLQ57LMIuLgKQ12RujGl0Oz9JbFMAHuBV2I/7ZykzGQPysSEqKCqG+kDc8VZ4AfIf/S8YnQk
xqdWQ5jLTIzXvcWd0WEYbDALBgcqhkjOOAQDBQADLwAwLAIUGP/oZpi79ZM1793XzZvnmrnmz5gC
FBm4bDN8h/0hAa83jaD8joLr098I
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
MIIC9jCCArSgAwIBAgIETo67pDALBgcqhkjOOAQDBQAwXjELMAkGA1UEBhMCVUsxEDAOBgNVBAgT
B1Vua25vd24xDzANBgNVBAcTBmxvbmRvbjENMAsGA1UEChMEYnVyYjENMAsGA1UECxMEYnVyYjEO
MAwGA1UEAxMFZmVyb3owHhcNMTExMDA3MDg0MzE2WhcNMTIwMTA1MDg0MzE2WjBeMQswCQYDVQQG
EwJVSzEQMA4GA1UECBMHVW5rbm93bjEPMA0GA1UEBxMGbG9uZG9uMQ0wCwYDVQQKEwRidXJiMQ0w
CwYDVQQLEwRidXJiMQ4wDAYDVQQDEwVmZXJvejCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB
HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/y
ZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq
7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7
+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4r
s6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKB
gQDKBDz1DFPPmmWp9n1FskJOev7CnnVFsKji1NLUDdifvS+uW+cnvnDfD3yPdxzUeknCrPTBRp+B
IvYUvLQ57LMIuLgKQ12RujGl0Oz9JbFMAHuBV2I/7ZykzGQPysSEqKCqG+kDc8VZ4AfIf/S8YnQk
xqdWQ5jLTIzXvcWd0WEYbDALBgcqhkjOOAQDBQADLwAwLAIUGP/oZpi79ZM1793XzZvnmrnmz5gC
FBm4bDN8h/0hAa83jaD8joLr098I
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/Organisationsportal/spring-security-saml/saml/SingleLogout"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8080/Organisationsportal/spring-security-saml/saml/SingleLogout"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8080/Organisationsportal/spring-security-saml/saml/SingleLogout"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/Organisationsportal/spring-security-saml/saml/SSO" index="0" isDefault="true"/>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="http://localhost:8080/Organisationsportal/spring-security-saml/saml/SSO" index="1" isDefault="false"/>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="http://localhost:8080/Organisationsportal/spring-security-saml/saml/SSO" index="2" isDefault="false"/>
</md:SPSSODescriptor>
ipd.xml:
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://localhost:8080/Organisationsportal" cacheDuration="PT1440M" ID="XpK4KzotwbSFUKx.-NtBzfGDWti">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
MIICRTCCAa6gAwIBAgIGAR0gYMbwMA0GCSqGSIb3DQEBBQUAMGYxCzAJBgNVBAYTAlVTMQswCQYD
VQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMQwwCgYDVQQKEwNEZXYxDTALBgNVBAsTBFBpbmcxHDAa
BgNVBAMTE0NvbmZpZyBTaWduaW5nIENlcnQwHhcNMDgxMDIxMTcwODEyWhcNMTMxMDIwMTcwODEy
WjBmMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ08xDzANBgNVBAcTBkRlbnZlcjEMMAoGA1UEChMD
RGV2MQ0wCwYDVQQLEwRQaW5nMRwwGgYDVQQDExNDb25maWcgU2lnbmluZyBDZXJ0MIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQDQeOdW6I2hyXCQn0X/+8/BzLfRfdy1kN54lmVauYEpaPHQo7by
gPPRPUTDC3LgJGfk4NWkPaM+EOeLzuVw9rbD3gjfsex6hUElkvUzPqXqNN3sq/2hm+FJup+GakE9
WCoEP5sGvlJshH00a4MSzjGTBBqqjsXaWDZ7Sy9UAGw5BQIDAQABMA0GCSqGSIb3DQEBBQUAA4GB
AKSNMImzVs7L+tfortt7RBFMzc/JLE8qnulY32FrWA3ZLrD+08EBeIp1iwdJ8AGpii3SFV3oV3xu
92Qy2WqsBwj1erYdKW5mrfAbThkwL5N7jRsjJyXnIcx3IBvRD+O+LIDHck0cSgmN14ghleeslx0Q
15kyBdoxbv6pR0k4xOaF
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleSignOnService Location="*1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"/>
<md:SingleLogoutService Location="*1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
</md:IDPSSODescriptor>
*1 I removed this because it from my company..
I dont know what I'am missing.
I definde a bean in the resource for the userDetailsService but my spring didnt know that im logged in.
Thanks
Marvin Thör

I could solve the problems I had.
I'll write my solution here.
resources.groovy
userDetailsService(OwnSpringSamlUserDetailsService){
samlUserService = ref("samlUserService")//This is a own Service
grailsApplication = ref("grailsApplication")
}
springSecurityService(OwnSpringSecurityService){
config = SpringSecurityUtils.securityConfig
authenticationTrustResolver = ref('authenticationTrustResolver')
grailsApplication = ref('grailsApplication')
passwordEncoder = ref('passwordEncoder')
objectDefinitionSource = ref('objectDefinitionSource')
userDetailsService = ref('userDetailsService')
userCache = ref('userCache')
}
The Problem here is that the saml spring override the getcurrentuser method.
BuildConfig.groovy
dependencies{
//SAML
compile('org.springframework.security.extensions:spring-security-saml2-core:1.0.2.RELEASE'){
export = false
}
compile('org.springframework.security:spring-security-core:3.2.9.RELEASE')
compile('org.springframework.security:spring-security-web:3.2.9.RELEASE')
}
plugins{
compile ":spring-security-core:2.0.0"
compile ":spring-security-saml:2.0.0"
}
The saml plugin used a old version of the spring core so I include the 3.2.9 Version to work with.
Config.groovy
grails.plugin.springsecurity.logout.filterProcessesUrl = "/saml/SingleLogout"
// Define the authentication providers
grails.plugin.springsecurity.providerNames = ["samlAuthenticationProvider"]
//SAML
grails.plugin.springsecurity.saml.metadata.sp.defaults = [
alias : 'localhost:dev:YOUR-APPNAME',
entityBaseURL: 'http://localhost:8080/YOUR-APPNAME'
]
grails.plugin.springsecurity.saml.metadata.url = "YOUR-METADATA-URL"
grails.plugin.springsecurity.saml.metadata.providers = ['ping': 'security/idp.xml']
you have to set the alias for the sp.xml. For me urls as alias not working.
UrlMapping.groovy
//SAML
"/saml/logout"(controller: 'logout', action: 'index')
I used this urlmapping for the logout
For the sp.xml I used the generated xml but I changed the entityID to:
localhost:dev:YOUR-APPNAME

Related

Why symfony container is build in test environment when I run phpunit whereas .env defines APP_ENV as dev?

I face a problem with env variables and running tests with phpunit on symfony 4.2 framework.
According to the documentation, .env and services.yaml are loaded first but if the APP_ENV is defined and set to a value like test, the container will be configured to load .env.test and services_test.yaml.
What I want to understand is : my .env files contains a key APP_ENV set to dev, but when I run phpunit to execute some tests, the environment is automatically (?) set to test...
To see that, I've dump $this->environment in the class Kernel.php.
bootstrap.php
<?php
use Symfony\Component\Dotenv\Dotenv;
require dirname(__DIR__).'/vendor/autoload.php';
// Load cached env vars if the .env.local.php file exists
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
if (is_array($env = #include dirname(__DIR__).'/.env.local.php')) {
$_SERVER += $env;
$_ENV += $env;
} elseif (!class_exists(Dotenv::class)) {
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
} else {
// load all the .env files
(new Dotenv())->loadEnv(dirname(__DIR__).'/.env');
}
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
.env
###> symfony/framework-bundle ###
APP_ENV=dev
...
Kernel.php
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
// Feel free to remove the "container.autowiring.strict_mode" parameter
// if you are using symfony/dependency-injection 4.0+ as it's the default behavior
$container->setParameter('container.autowiring.strict_mode', true);
$container->setParameter('container.dumper.inline_class_loader', true);
$confDir = $this->getProjectDir().'/config';
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
dump($this->environment); //print "test"
}
phpunit.xml.dist
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="config/bootstrap.php"
>
<php>
<ini name="error_reporting" value="-1" />
<server name="KERNEL_CLASS" value="AppBundle\Kernel" />
<!-- ###+ symfony/framework-bundle ### -->
<env name="APP_ENV" value="dev" force="true"/> <!-- doesn't work with or without force="true" -->
<!-- env name="TRUSTED_PROXIES" value="127.0.0.1,127.0.0.2" -->
<!-- env name="TRUSTED_HOSTS" value="'^localhost|example\.com$'" -->
<!-- ###- symfony/framework-bundle ### -->
<!-- ###+ doctrine/doctrine-bundle ### -->
<!-- Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url -->
<!-- For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" -->
<!-- Configure your db driver and server_version in config/packages/doctrine.yaml -->
<env name="DATABASE_URL" value="sqlite:///%kernel.project_dir%/app/test.db"/>
<!-- ###- doctrine/doctrine-bundle ### -->
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src</directory>
<exclude>
<directory>src/*Bundle/Resources</directory>
<directory>src/*/*Bundle/Resources</directory>
<directory>src/*/Bundle/*Bundle/Resources</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
Could you give me a clue about what happens, why my container is configure in test environment instead of the value of the APP_ENV?

My Archetypes-based content type can't be added

I'm developing an add-on package which introduces a few Archetypes-based content types;
these are defined in the default profile of that package.
After (re-) installing my package in the Quick-Installer, I can see my types in the types tool; but I can't add them TTW, and they are not listed in the folder_constraintypes_form. I did select them in the "Allowed content types" multiselect list of the Folder portal type.
Since I got a ValueError from FactoryTypeInformation._getFactoryMethod in an bin/instance debug session, I "developed" Products.CMFPlone (branch 2.2) and changed the TypesTool.py like so:
from pprint import pprint # ADDED
...
class FactoryTypeInformation(TypeInformation):
...
def _getFactoryMethod(self, container, check_security=1):
if not self.product or not self.factory:
raise ValueError, ('Product factory for %s was undefined' %
self.getId())
pd = container.manage_addProduct # ADDED
p = container.manage_addProduct[self.product]
self_product = self.product # ADDED
self_factory = self.factory # ADDED
m = getattr(p, self.factory, None)
if m is None:
pprint(locals()) # ADDED
raise ValueError, ('Product factory for %s was invalid' %
self.getId())
if not check_security:
return m
if getSecurityManager().validate(p, p, self.factory, m):
return m
raise AccessControl_Unauthorized( 'Cannot create %s' % self.getId() )
The debug session now looks like this:
>>> root = app.plone
>>> from Products.CMFCore.utils import getToolByName
>>> tmp_folder = root.temp
>>> type_name = 'MyType'
>>> types_tool = getToolByName(tmp_folder, 'portal_types')
>>> type_info = types_tool.getTypeInfo(type_name)
>>> type_info
<DynamicViewTypeInformation at /plone/portal_types/MyType>
>>> new_content_item = type_info._constructInstance(tmp_folder, 'shiny_new_object')
{'check_security': 0,
'container': <ATFolder at /plone/temp>,
'pd': <App.FactoryDispatcher.ProductDispatcher object at 0x227afd0>,
'p': <App.FactoryDispatcher.FactoryDispatcher object at 0x7b97450>,
'self': <DynamicViewTypeInformation at /plone/portal_types/MyType>,
'm': None,
'self_factory': 'addMyType',
'self_product': 'MyCompany.MyProduct'}
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/opt/zope/instances/zope-devel/src/Products.CMFCore/Products/CMFCore/TypesTool.py", line 551, in _constructInstance
m = self._getFactoryMethod(container, check_security=0)
File "/opt/zope/instances/zope-devel/src/Products.CMFCore/Products/CMFCore/TypesTool.py", line 467, in _getFactoryMethod
self.getId())
ValueError: Product factory for MyType was invalid
So, the FactoryDispatcher lacks the necessary addMyType attribute.
Probably my declarations are incomplete?
This is what I have:
config.py:
# -*- coding: utf-8 -*-
from Products.CMFCore.permissions import setDefaultRoles
from os import sep
from .permissions import (AddMyType,
)
PROJECTNAME = "MyCompany.MyProduct"
PRODUCT_HOME = sep.join(__file__.split(sep)[:-1])
MANAGERS_ONLY = ('Manager',)
MANAGERS_AND_OWNER = ('Manager', 'Owner')
# Permissions
DEFAULT_ADD_CONTENT_PERMISSION = "Add portal content"
setDefaultRoles(DEFAULT_ADD_CONTENT_PERMISSION, MANAGERS_AND_OWNER)
ADD_CONTENT_PERMISSIONS = {
'MyType': AddMyType,
}
for perm in ADD_CONTENT_PERMISSIONS.values():
setDefaultRoles(perm, MANAGERS_ONLY)
content/mytype.py:
# -*- coding: utf-8 -*-
__author__ = """unknown <unknown>"""
__docformat__ = 'plaintext'
from AccessControl import ClassSecurityInfo
from zope.interface import implements
from ..interfaces import IMyType
from ..config import PROJECTNAME
from Products.ATContentTypes.content.base import ATCTContent
from Products.ATContentTypes.content.schemata import ATContentTypeSchema
from Products.ATContentTypes.content.base import registerATCT as registerType
MyType_schema = (
ATContentTypeSchema.copy()
)
class MyType(ATCTContent):
"""
description of my type
"""
security = ClassSecurityInfo()
implements(IMyType)
meta_type = 'MyType'
_at_rename_after_creation = True
schema = MyType_schema
registerType(MyType, PROJECTNAME)
interfaces.py:
# -*- coding: utf-8 -*-
"""Module where all interfaces, events and exceptions live."""
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.interface import Interface
class ISupBetonqualiLayer(IDefaultBrowserLayer):
"""Marker interface that defines a browser layer."""
class IMyType(Interface):
"""Marker interface for .mytype.MyType
"""
permissions.py:
# -*- coding: utf-8 -*- vim: ts=8 sts=4 sw=4 si et tw=79
"""
Permissions
"""
AddMyType = 'MyCompany.MyProduct: Add MyType'
profiles/default/factorytool.xml:
<?xml version="1.0"?>
<object name="portal_factory" meta_type="Plone Factory Tool">
<factorytypes>
<type portal_type="MyType"/>
</factorytypes>
</object>
profiles/default/rolemap.xml:
<?xml version="1.0"?>
<rolemap>
<roles>
<role name="MyAuthor"/>
</roles>
<permissions>
<permission name="MyCompany.MyProduct: Add MyType" acquire="True">
<role name="MyAuthor"/>
<role name="Manager"/>
</permission>
</permissions>
</rolemap>
profiles/default/types.xml:
<?xml version="1.0"?>
<object name="portal_types"
meta_type="Plone Types Tool">
<object name="MyType"
meta_type="Factory-based Type Information with dynamic views"/>
</object>
profiles/default/types/MyType.xml:
<?xml version="1.0"?>
<object name="MyType"
meta_type="Factory-based Type Information with dynamic views"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title">MyType</property>
<property name="description">
Some description text which is indeed visible in the types tool
</property>
<property name="content_icon">SomeExisting.png</property>
<property name="content_meta_type">MyType</property>
<property name="product">MyCompany.MyProduct</property>
<property name="factory">addMyType</property>
<property name="immediate_view">mytype_view</property>
<property name="global_allow">True</property>
<property name="filter_content_types">False</property>
<property name="allowed_content_types">
</property>
<property name="allow_discussion">False</property>
<property name="default_view">mytype_view</property>
<property name="view_methods">
<element value="base_view"/>
</property>
<property name="default_view_fallback">False</property>
<alias from="(Default)" to="(dynamic view)"/>
<alias from="index.html" to="(dynamic view)"/>
<alias from="view" to="(selected layout)"/>
<alias from="edit" to="base_edit"/>
<alias from="properties" to="base_metadata"/>
<action title="View"
action_id="view"
category="object"
condition_expr=""
url_expr="string:${object_url}/view"
visible="True">
<permission value="View"/>
</action>
<action title="Edit"
action_id="edit"
category="object"
condition_expr="not:object/##plone_lock_info/is_locked_for_current_user"
url_expr="string:${object_url}/edit"
visible="True">
<permission value="Modify portal content"/>
</action>
</object>
Should not Archetypes take care of creating that missing addMyType method?
What could make this fail?
Is there something obviously missing in my configuration?
The site contains Archtypes-based objects exclusively so far. Will I come into trouble if I add Dexterity-based types now? ''(I'm totally inexperienced with Dexterity)''
Before someone tells me to do so: I created a question in the Plone community forum already; no luck so far. If important information comes in on either page, I'll sync it.
These are the missing parts to make your contenttype addable:
1.) Register the content-directory in MyCompany/MyProduct/configure.zcml by adding:
<include package=".content" />
2.) Add the file MyCompany/MyProduct/content/configure.zcml with this content:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five"
i18n_domain="MyCompany.MyProduct">
<class class=".mytype.MyType">
<require
permission="zope2.View"
interface="..interfaces.IMyType"
/>
</class>
</configure>
3.) Fix the then occurring syntax-error in MyCompany/MyProduct/content/mytype.py by replacing class MyType(*basecls) with class MyType(ATCTContent).
And last but not least remove the former attempts of making things work. Best would be to outsource the type to a dedicated pckg and create it with zopeskel, imo.
For the view-error occurring after adding a type, feel free to open a new quest ;-)

Alfresco workflow get triggered multiple times

I am facing problem in triggering workflow.
I have applied rule on a Folder
Definition of rule :
i) When Item are created on enter this folder
ii) Name End With .xml
iii)Execute Script
Script is
function startWorkflow()
{
var workflow = actions.create("start-workflow");
workflow.parameters.workflowName = "activiti$Excel_initial_service";
workflow.parameters["bpm:workflowDescription"] = "Excel initial service workflow for : " + document.name;
var futureDate = new Date();
futureDate.setDate(futureDate.getDate() + 1);
workflow.parameters["bpm:workflowDueDate"] = futureDate;
return workflow.execute(document);
}
function main()
{
startWorkflow();
}
main();
and my workflow definition is
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="Excel_initial_service" name="Excel Initial Service" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
.
.
.
.
<serviceTask id="servicetask1" name="Service Task" activiti:class="*"> </serviceTask>
.
.
.
.
The problem i am facing is service task is getting triggered multiple times for single file entered in the folder and its not getting stopped.
<?xml version="1.0" encoding="UTF-8"?>
<process id="***" name="Excel Generation Service" isExecutable="true">
<startEvent id="starteventexcel1" name="Start"></startEvent>
<intermediateCatchEvent id="timerintermediatecatcheventexcel1" name="TimerCatchEvent1">
<timerEventDefinition>
<timeDuration>PT10S</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
<serviceTask id="servicetaskexcel1" name="Service Task" activiti:class="***"></serviceTask>
<intermediateCatchEvent id="timerintermediatecatcheventexcel2" name="TimerCatchEvent2">
<timerEventDefinition>
<timeDuration>PT10S</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
<endEvent id="endeventexcel1" name="End"></endEvent>
<sequenceFlow id="flowexcel1" sourceRef="starteventexcel1" targetRef="timerintermediatecatcheventexcel1"></sequenceFlow>
<sequenceFlow id="flowexcel2" sourceRef="timerintermediatecatcheventexcel1" targetRef="servicetaskexcel1"></sequenceFlow>
<sequenceFlow id="flowexcel3" sourceRef="servicetaskexcel1" targetRef="timerintermediatecatcheventexcel2"></sequenceFlow>
<sequenceFlow id="flowexcel4" sourceRef="timerintermediatecatcheventexcel2" targetRef="endeventexcel1"></sequenceFlow>
</process>
The first intermediateCatchEvent here will execute your service task every 10 sec. Why using it?
this answer may this will help you.
The class to use is the ClockUtil which changes the internal clock of the engine.
That being said, I checked your test and I saw that you are using the
ProcessEngine eng = ProcessEngineConfiguration
.createStandaloneInMemProcessEngineConfiguration()
.buildProcessEngine();
To get the process engine. That will give you a default engine, with the job executor disabled. The job executor is needed for timer execution. Add following line to building the process engine to make it work:
setJobExecutorActivate(true);
You can refer this question https://community.alfresco.com/thread/219801-problem-with-intermediatecatchevent
you will find some code on github as explained in above referred question https://github.com/Activiti/Activiti/blob/master/modules/activiti-engine/src/test/java/org/activiti/engine/test/bpmn/event/timer/IntermediateTimerEventTest.java

How to make dexterity modifications available to other clients?

The modified model_source of a dexterity type is not available for other clients until the other client restarts.
Invalidating or clearing the SCHEMA_CACHE is not a working solution: every client seems to have its own SCHEMA_CACHE which afik cannot be cleared or invalidated from another client.
Is there any solution to solve this problem?
The scenario presented here uses ipython as second client. The same can be reproduced through the web by starting two clients: (1) create a dexterity type in client1, and (2) edit the XML Field Model in client2.
I'd like to put this as an issue on https://github.com/plone/plone.dexterity but as for today issues seem not to be available in the plone.dexterity github project
utils.sync()
from Products.CMFCore.utils import getToolByName
from plone.dexterity.fti import DexterityFTI
id = 'mydexteritytype'
plone_site = app.Plone
tool_portal_types = getToolByName(plone_site, 'portal_types')
if tool_portal_types.hasObject(id): tool_portal_types.manage_delObjects(id)
utils.commit()
utils.sync()
fti = DexterityFTI(id)
fti.id = id
data = {}
data['title'] = id
data['i18n_domain'] = 'plone'
data['behaviors'] = "\n".join([
'plone.app.dexterity.behaviors.metadata.IDublinCore',
'plone.app.content.interfaces.INameFromTitle',
])
data['model_source'] = '''
<model xmlns:security="http://namespaces.plone.org/supermodel/security"
xmlns:marshal="http://namespaces.plone.org/supermodel/marshal"
xmlns:form="http://namespaces.plone.org/supermodel/form"
xmlns="http://namespaces.plone.org/supermodel/schema">
<schema>
<field name="original" type="zope.schema.TextLine">
<default>original</default>
<description/>
<title>original</title>
</field>
</schema>
</model>'''
data['klass'] = 'plone.dexterity.content.Container'
data['filter_content_types'] = True
data['icon_expr'] = 'string:${portal_url}/document_icon.png'
fti.manage_changeProperties(**data)
tool_portal_types._setObject(fti.id, fti)
utils.commit()
After running the code above, the new created mydexteritytype is available for all other clients.
The modifications produced by the following code will be only available in the client running the code. All other clients are not aware of the changes.
utils.sync()
from plone.dexterity.interfaces import IDexterityFTI
from zope.component import getUtility
fti = getUtility(IDexterityFTI, name=id)
model_source = '''
<model xmlns:security="http://namespaces.plone.org/supermodel/security"
xmlns:marshal="http://namespaces.plone.org/supermodel/marshal"
xmlns:form="http://namespaces.plone.org/supermodel/form"
xmlns="http://namespaces.plone.org/supermodel/schema">
<schema>
<field name="modified" type="zope.schema.TextLine">
<default>modified</default>
<description/>
<title>modified</title>
</field>
</schema>
</model>'''
fti.manage_changeProperties(model_source=model_source)
from plone.dexterity.schema import SCHEMA_CACHE
SCHEMA_CACHE.invalidate(fti)
SCHEMA_CACHE.clear()
utils.commit()
This pull-request is supposed to fix this issue:
https://github.com/plone/plone.dexterity/pull/137

BlazeDS Messaging Channel.Connect.Failed Error

I searched through the internet and any answer for this error could not solved my problem.
I have a blazeds server in Openshift and I'm connecting to it via Flash Builder.
I want to make an app that will send a message to all other users who are using my app.
I mean I have 2 applications. One will send a message to server and this one will be on Desktop, the other one is a mobile project and will receive messages that I sent from desktop app through server.
I tried to use BlazeDS messaging but it's giving me this error:
(mx.messaging.messages::ErrorMessage)#0
body = (Object)#1
clientId = (null)
correlationId = "96461BC6-7288-A95C-923B-B32FCDDC9CE3"
destination = ""
extendedData = (null)
faultCode = "Client.Error.MessageSend"
faultDetail = "Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed: url: 'http://ainApp.swf/messagebroker/amfpolling'"
faultString = "Send failed"
headers = (Object)#2
messageId = "147C1B6F-6877-79D8-3BCA-B32FCDF5E3F9"
rootCause = (mx.messaging.events::ChannelFaultEvent)#3
bubbles = false
cancelable = false
channel = (mx.messaging.channels::AMFChannel)#4
authenticated = false
channelSets = (Array)#5
connected = false
connectTimeout = -1
enableSmallMessages = true
endpoint = "http://ainApp.swf/messagebroker/amfpolling"
failoverURIs = (Array)#6
id = "my-polling-amf"
mpiEnabled = false
netConnection = (flash.net::NetConnection)#7
client = (mx.messaging.channels::AMFChannel)#4
connected = false
httpIdleTimeout = 0
maxPeerConnections = 8
objectEncoding = 3
proxyType = "none"
uri = "http://ainApp.swf/messagebroker/amfpolling"
piggybackingEnabled = false
polling = false
pollingEnabled = true
pollingInterval = 4000
protocol = "http"
reconnecting = false
recordMessageSizes = false
recordMessageTimes = false
requestTimeout = -1
uri = "http://{server.name}:{server.port}/messagebroker/amfpolling"
url = "http://{server.name}:{server.port}/messagebroker/amfpolling"
useSmallMessages = false
channelId = "my-polling-amf"
connected = false
currentTarget = (mx.messaging.channels::AMFChannel)#4
eventPhase = 2
faultCode = "Channel.Connect.Failed"
faultDetail = "NetConnection.Call.Failed: HTTP: Failed: url: 'http://ainApp.swf/messagebroker/amfpolling'"
faultString = "error"
reconnecting = false
rejected = false
rootCause = (Object)#8
code = "NetConnection.Call.Failed"
description = "HTTP: Failed"
details = "http://ainApp.swf/messagebroker/amfpolling"
level = "error"
target = (mx.messaging.channels::AMFChannel)#4
type = "channelFault"
timestamp = 0
timeToLive = 0
This is my desktop application that I'm trying to send messages from:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.messaging.events.ChannelEvent;
import mx.messaging.events.MessageFaultEvent;
import mx.messaging.messages.AsyncMessage;
protected function cons_faultHandler(event:MessageFaultEvent):void
{
trace(event.message + ' fault')
}
]]>
</fx:Script>
<fx:Declarations>
<s:Consumer id="cons" destination="cricket" message="messages.text += event.message.body.msg + '\n'" fault="cons_faultHandler(event)"/>
<s:Producer id="prod" destination="cricket" fault="cons_faultHandler(event)" />
</fx:Declarations>
<s:VGroup verticalScrollPosition="0" horizontalScrollPosition="0">
<s:TextArea id="messages" width="100%" height="50%"/>
<s:TextInput id="mesgSender" />
<s:Button id="send" label="send" click="prod.send(new AsyncMessage({msg:mesgSender.text+'asdasd'}))"/>
</s:VGroup>
</s:WindowedApplication>
And this are my messaging-config.xml and services-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service-include file-path="remoting-config.xml" />
</services>
<security>
<login-command class="flex.messaging.security.TomcatLoginCommand" server="Tomcat"/>
</security>
<channels>
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Error">
<properties>
<prefix>[BlazeDS] </prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
<filters>
<pattern>Endpoint.*</pattern>
<pattern>Service.*</pattern>
<pattern>Configuration</pattern>
</filters>
</target>
</logging>
<system>
<redeploy>
<enabled>false</enabled>
</redeploy>
</system>
</services-config>
<?xml version="1.0" encoding="UTF-8"?>
<service id="message-service"
class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
<!-- <adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/> -->
</adapters>
<default-channels>
<channel ref="my-polling-amf"/>
</default-channels>
<destination id="cricket">
<channel ref="my-amf"/>
</destination>
</service>
I don't know what I'm doing wrong and why in error message, the endpoint url is "http://ainApp.swf/messagebroker/amfpolling". My desktop apps name is MainApp by the way.
Thanks
In services-config.xml you should define your channel url.
url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
to like this
url="/yourContextRootName/messagebroker/amf"
Do not define server.name and server.port, it comes with similar problem.

Resources