mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-15 15:02:20 +00:00
Merged WEBAPP-API (5.2.1) to 5.2.N (5.2.1)
135590 jkaabimofrad: APPSREPO-35: Added password reset V1 API. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@135930 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -42,4 +42,5 @@
|
||||
<import resource="classpath*:alfresco/repo-clients-apps-context.xml" />
|
||||
<import resource="classpath*:alfresco/domain/*-context.xml" />
|
||||
<import resource="classpath*:alfresco/smartfolder-context.xml" />
|
||||
<import resource="classpath*:alfresco/reset-password-context.xml" />
|
||||
</beans>
|
||||
|
@@ -215,6 +215,14 @@
|
||||
<prop key="mimetype">text/xml</prop>
|
||||
<prop key="redeploy">false</prop>
|
||||
</props>
|
||||
|
||||
<!-- Activiti reset password workflow definition -->
|
||||
<props>
|
||||
<prop key="engineId">activiti</prop>
|
||||
<prop key="location">alfresco/workflow/reset-password_processdefinition.bpmn20.xml</prop>
|
||||
<prop key="mimetype">text/xml</prop>
|
||||
<prop key="redeploy">false</prop>
|
||||
</props>
|
||||
</list>
|
||||
</property>
|
||||
<property name="models">
|
||||
@@ -223,6 +231,7 @@
|
||||
<value>alfresco/workflow/invitation-nominated-workflow-model.xml</value>
|
||||
<value>alfresco/workflow/invitation-moderated-workflow-model.xml</value>
|
||||
<value>alfresco/workflow/publishingWorkflowModel.xml</value>
|
||||
<value>alfresco/workflow/reset-password-workflow-model.xml</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="labels">
|
||||
|
@@ -1,9 +1,20 @@
|
||||
# registry of clients that are able to email
|
||||
|
||||
repo.client-app.share.templateAssetsUrl=${shareUrl}/res/components/images/
|
||||
repo.client-app.share.sharedLinkBaseUrl=${shareUrl}/s
|
||||
# the path could be:
|
||||
## NOTE: when setting the email template path, the value could be:
|
||||
# an XPATH (e.g. app:company_home/app:dictionary/app:email_templates/example-email.ftl)
|
||||
# a NodeRef of the template
|
||||
# a class path of the template
|
||||
|
||||
# template assets url for share client
|
||||
repo.client-app.share.templateAssetsUrl=${shareUrl}/res/components/images/
|
||||
# shared-link (quickShare) base url
|
||||
repo.client-app.share.sharedLinkBaseUrl=${shareUrl}/s
|
||||
# shared-link email template path
|
||||
repo.client-app.share.sharedLinkTemplatePath=
|
||||
|
||||
# reset password request email template path
|
||||
repo.client-app.share.requestResetPasswordTemplatePath=
|
||||
# reset password UI page url
|
||||
repo.client-app.share.resetPasswordPageUrl=${shareUrl}/page/reset-password
|
||||
# reset password confirmation email template path
|
||||
repo.client-app.share.confirmResetPasswordTemplatePath=
|
15
config/alfresco/messages/reset-password-messages.properties
Normal file
15
config/alfresco/messages/reset-password-messages.properties
Normal file
@@ -0,0 +1,15 @@
|
||||
# Email subjects.
|
||||
reset-password-request.email.subject=Reset your password
|
||||
reset-password-confirmation.email.subject=Password reset successful
|
||||
|
||||
# Request reset password email
|
||||
templates.reset-password-email.ftl.title=Reset your password
|
||||
templates.reset-password-email.ftl.detail=You recently requested to change the password for your account.
|
||||
templates.reset-password-email.ftl.ignore_message=If you didn't request a password reset or you don't want to change it, you can ignore and delete this message, and your account will remain secure.
|
||||
templates.reset-password-email.ftl.having_trouble_clicking_button=If you're having trouble clicking on the Reset Password button, just copy and paste the following URL into your web browser:
|
||||
templates.reset-password-email.ftl.reset_password_button=Reset password
|
||||
|
||||
# Reset password confirmation email
|
||||
templates.reset-password-confirm-email.ftl.title=Password reset successful
|
||||
templates.reset-password-confirm-email.ftl.detail=The password for your Alfresco account was recently changed.
|
||||
templates.reset-password-confirm-email.ftl.note=If you didn't request a password reset, please contact your administrator immediately.
|
@@ -1228,3 +1228,7 @@ category.queryFetchSize=5000
|
||||
authentication.protection.enabled=true
|
||||
authentication.protection.limit=10
|
||||
authentication.protection.periodSeconds=6
|
||||
|
||||
system.email.sender.default=noreply@alfresco.com
|
||||
# reset password workflow will expire in an hour
|
||||
system.reset-password.endTimer=PT1H
|
||||
|
40
config/alfresco/reset-password-context.xml
Normal file
40
config/alfresco/reset-password-context.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
<bean id="resetPasswordService" class="org.alfresco.repo.security.authentication.ResetPasswordServiceImpl">
|
||||
<property name="workflowService" ref="WorkflowService" />
|
||||
<property name="activitiHistoryService" ref="activitiHistoryService" />
|
||||
<property name="actionService" ref="actionService" />
|
||||
<property name="nodeService" ref="nodeService" />
|
||||
<property name="personService" ref="personService" />
|
||||
<property name="sysAdminParams" ref="sysAdminParams"/>
|
||||
<property name="activitiTaskService" ref="activitiTaskService" />
|
||||
<property name="authenticationService" ref="AuthenticationService" />
|
||||
<property name="clientAppConfig" ref="clientAppConfig" />
|
||||
<property name="emailHelper" ref="emailHelper" />
|
||||
<property name="timerEnd" value="${system.reset-password.endTimer}" />
|
||||
<property name="defaultEmailSender" value="${system.email.sender.default}" />
|
||||
</bean>
|
||||
|
||||
<bean id="resetPaswwordResourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
|
||||
<property name="resourceBundles">
|
||||
<list>
|
||||
<value>alfresco.messages.reset-password-messages</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="baseResetPasswordDelegate" parent="baseJavaDelegate" abstract="true">
|
||||
<property name="resetPasswordService" ref="resetPasswordService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="SendResetPasswordEmailDelegate" parent="baseResetPasswordDelegate"
|
||||
class="org.alfresco.repo.security.authentication.activiti.SendResetPasswordEmailDelegate">
|
||||
</bean>
|
||||
|
||||
<bean id="PerformResetPasswordDelegate" parent="baseResetPasswordDelegate"
|
||||
class="org.alfresco.repo.security.authentication.activiti.PerformResetPasswordDelegate">
|
||||
</bean>
|
||||
</beans>
|
@@ -0,0 +1,450 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
td {
|
||||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
width: 100% ! important;
|
||||
height: 100% !important;
|
||||
color: #727174;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #727174;
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0c79bf;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.linkone {
|
||||
color: #0c79bf;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.appleLinks a {
|
||||
color: #0c79bf;
|
||||
}
|
||||
|
||||
.appleLinksWhite a {
|
||||
color: #0c79bf;
|
||||
}
|
||||
|
||||
.force-full-width {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.body-padding {
|
||||
padding: 0 75px
|
||||
}
|
||||
|
||||
.force-width-80 {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
p {
|
||||
Margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.button {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.button a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 600px;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
|
||||
#outlook a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ReadMsgBody {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.backgroundTable {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table td {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.ExternalClass * {
|
||||
line-height: 115%;
|
||||
}
|
||||
|
||||
.ExternalClass {
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
/*]]>*/
|
||||
</style>
|
||||
<style type="text/css" media="screen">
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { {
|
||||
@-ms-viewport {
|
||||
width: 320px;
|
||||
}
|
||||
@viewport {
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style type="text/css" media="screen">
|
||||
@media screen {
|
||||
* {
|
||||
font-family: 'Helvetica Neue', 'Arial', 'sans-serif' !important;
|
||||
}
|
||||
|
||||
.w280 {
|
||||
width: 280px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style type="text/css" media="only screen and (max-width: 480px)">
|
||||
@media only screen and (max-width: 480px) {
|
||||
.full {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table[class*="w320"] {
|
||||
width: 320px !important;
|
||||
}
|
||||
|
||||
td[class*="w320"] {
|
||||
width: 280px !important;
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
}
|
||||
|
||||
img[class*="w320"] {
|
||||
width: 250px !important;
|
||||
height: 67px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-spacing"] {
|
||||
padding-top: 10px !important;
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-hide"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-br"] {
|
||||
font-size: 8px !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-brh"] {
|
||||
font-size: 1px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-w20"] {
|
||||
width: 20px !important;
|
||||
}
|
||||
|
||||
img[class*="mobile-w20"] {
|
||||
width: 20px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-center"] {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
table[class*="w100p"] {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
td[class*="activate-now"] {
|
||||
padding-right: 0 !important;
|
||||
padding-top: 20px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-resize"] {
|
||||
font-size: 22px !important;
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body offset="0" class="body" style="padding:0; margin:0; display:block; background:#f3f4f4; -webkit-text-size-adjust:none; " bgcolor="#EEEEEE">
|
||||
<table align="center" cellpadding="0" cellspacing="0" width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="top" style="background-color:#f3f4f4; " width="100%">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320">
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
|
||||
<!--Snippet Block-->
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="10" width="100%" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<table align="center" width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td align="right">
|
||||
<div style="display:none;font-size:1px;color:#333333;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">
|
||||
-
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Header Block-->
|
||||
<table bgcolor="#FFFFFF" border="0" cellspacing="0" cellpadding="0" align="center" width="100%"
|
||||
style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; border-bottom:solid 1px #dedee4; border-top:solid 1px #dedee4; width:100%!important; min-width:100%;">
|
||||
<tr style="width:100%;">
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="10" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="left" valign="middle"><a style="color: #ffffff; text-decoration: none;" href=
|
||||
"http://go.alfresco.com/a0100K050L0000KZjI2d00U" target="_blank"
|
||||
><span style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; color: #727174;"><img
|
||||
style="border:none; display:block; border-collapse:collapse; outline:none; text-decoration:none;"
|
||||
src="${template_assets_url}/Alfresco_Logo_gray.png" border="0"
|
||||
alt="Alfresco" width="122" height="38"></span></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td align="right" bgcolor="#FFFFFF">
|
||||
<table border="0" cellspacing="0" cellpadding="10" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="right" valign="middle"><span
|
||||
style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; font-weight:200; color: #727174;">make business flow</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Body Block 1-->
|
||||
<!--Banner Block-->
|
||||
<table cellspacing="0" cellpadding="0" width="100%" style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; ">
|
||||
<tr>
|
||||
<td style="border-collapse:collapse; ">
|
||||
<table cellspacing="0" cellpadding="0" width="100%" style="background-color:#0c79bf; border:none; ">
|
||||
<tr>
|
||||
<td style="border-collapse:collapse; ">
|
||||
<div class="mktEditable" id="Banner Image 1"><span
|
||||
style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; color: #ffffff;"><img
|
||||
src="${template_assets_url}/Product_Banner_1.jpg" alt="Alfresco Products" style="width:100%; border:none;
|
||||
display:block; border-collapse:collapse; outline:none; text-decoration:none;"></span></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--Copy-->
|
||||
<table cellspacing="0" cellpadding="0" align="center" bgcolor="#FFFFFF"
|
||||
style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; border-bottom:solid 1px #dedee4; " width="100%">
|
||||
<tr align="center">
|
||||
<td style="background-color:#ffffff; " align="center">
|
||||
<table class="force-width-80" cellspacing="0" cellpadding="12" align="center" bgcolor="#FFFFFF" width="80%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<!--Headline Text-->
|
||||
<div class="mktEditable" id="Headline Text 1" align="left" style="vertical-align:middle; "><span
|
||||
style="color: #727174; margin: 0px; font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 22px; font-weight: 600; text-align: left; text-decoration: none; vertical-align:
|
||||
middle;"><p>${message("templates.reset-password-confirm-email.ftl.title")}</p></span></div>
|
||||
<div class="mktEditable" id="Body Text 1" align="left"><span
|
||||
style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:18px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<p>${message("templates.generic-email.ftl.salutation", userName)?html}</p>
|
||||
<p>${message("templates.reset-password-confirm-email.ftl.detail")}</p>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="5">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Button-->
|
||||
<table style="margin:0 auto; " cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align:center; margin:0 auto; ">
|
||||
<div><!--[if mso]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
style="height:45px;v-text-anchor:middle;width:220px;" stroke="f"
|
||||
fillcolor="#47AA2">
|
||||
<w:anchorlock/>
|
||||
<center>
|
||||
<![endif]-->
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:12px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<p>${message("templates.reset-password-confirm-email.ftl.note")}</p>
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:12px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<hr>
|
||||
</span>
|
||||
<!--[if mso]>
|
||||
</center>
|
||||
</v:rect>
|
||||
<![endif]--></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="5">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Footer Block-->
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table cellspacing="0" cellpadding="0" border="0" align="center">
|
||||
<tr>
|
||||
<td cellspacing="0" cellpadding="0" border="0" align="center"><a
|
||||
style="color: #ffffff; text-decoration: none;"
|
||||
href="http://go.alfresco.com/a0100K060L0000RZeI2o00U" target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_Twitter.png" width="23" height="23"
|
||||
border="0"></a> <a style="color: #ffffff; text-decoration: none;"
|
||||
href="http://go.alfresco.com/G6I0Zo100S0fL0UK0000020"
|
||||
target="_blank"><img src="${template_assets_url}/Alfresco_Icon_Social_LinkedIn.png"
|
||||
width="23" height="23" border="0"></a> <a
|
||||
style="color:
|
||||
#ffffff; text-decoration: none;" href="http://go.alfresco.com/TT2Lo00060000Ig10K00UZ0" target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_Facebook.png" width="23" height="23" border="0"></a> <a
|
||||
style="color: #ffffff; text-decoration: none;"
|
||||
href="http://go.alfresco.com/v00002oh0UKZL0U6I010000" target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_Google.png" width="23" height="23" border="0"></a></td>
|
||||
<td cellspacing="0" cellpadding="0" border="0" align="center" width="10"></td>
|
||||
<td cellspacing="0" cellpadding="0" border="0" align="center"><a style="color: #333333;"
|
||||
href="http://go.alfresco.com/a0100K050L0000KZjI2d00U"
|
||||
target="_blank"><span
|
||||
style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #727174;"><img
|
||||
src="${template_assets_url}/AlfrescoGlobal_Logo_BW.png" border="0" alt="alfresco.com" width="92" height="29"><br></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a style="color: #0c79bf; text-decoration: underline;" href="http://www.alfresco.com/company/contact"
|
||||
target="_blank"><span
|
||||
style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #0c79bf;">${message("templates.generic-email.ftl.contact_us")}</span></a>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial,
|
||||
sans-serif; font-size: 10px; color: #b3b3b8;">© ${date?string["yyyy"]} Alfresco Software, Inc.
|
||||
${message("templates.generic-email.ftl.copy_right")}</span><br>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #b3b3b8;">Bridge Ave, The Place Maidenhead SL6 1AF United Kingdom</span><br>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #b3b3b8;">1825 S Grant St, Suite 900 San Mateo, CA 94402 USA</span><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--Litmus Tracking-->
|
||||
<table style="display: none;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 0px; display: none; overflow: hidden; max-height: 0px;">{{my.Litmus_Code}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,455 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
td {
|
||||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
width: 100% ! important;
|
||||
height: 100% !important;
|
||||
color: #727174;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #727174;
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0c79bf;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.linkone {
|
||||
color: #0c79bf;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.appleLinks a {
|
||||
color: #0c79bf;
|
||||
}
|
||||
|
||||
.appleLinksWhite a {
|
||||
color: #0c79bf;
|
||||
}
|
||||
|
||||
.force-full-width {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.body-padding {
|
||||
padding: 0 75px
|
||||
}
|
||||
|
||||
.force-width-80 {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
p {
|
||||
Margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.button {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.button a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 600px;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
|
||||
#outlook a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ReadMsgBody {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.backgroundTable {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table td {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.ExternalClass * {
|
||||
line-height: 115%;
|
||||
}
|
||||
|
||||
.ExternalClass {
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
/*]]>*/
|
||||
</style>
|
||||
<style type="text/css" media="screen">
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { {
|
||||
@-ms-viewport {
|
||||
width: 320px;
|
||||
}
|
||||
@viewport {
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style type="text/css" media="screen">
|
||||
@media screen {
|
||||
* {
|
||||
font-family: 'Helvetica Neue', 'Arial', 'sans-serif' !important;
|
||||
}
|
||||
|
||||
.w280 {
|
||||
width: 280px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style type="text/css" media="only screen and (max-width: 480px)">
|
||||
@media only screen and (max-width: 480px) {
|
||||
.full {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table[class*="w320"] {
|
||||
width: 320px !important;
|
||||
}
|
||||
|
||||
td[class*="w320"] {
|
||||
width: 280px !important;
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
}
|
||||
|
||||
img[class*="w320"] {
|
||||
width: 250px !important;
|
||||
height: 67px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-spacing"] {
|
||||
padding-top: 10px !important;
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-hide"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-br"] {
|
||||
font-size: 8px !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-brh"] {
|
||||
font-size: 1px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-w20"] {
|
||||
width: 20px !important;
|
||||
}
|
||||
|
||||
img[class*="mobile-w20"] {
|
||||
width: 20px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-center"] {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
table[class*="w100p"] {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
td[class*="activate-now"] {
|
||||
padding-right: 0 !important;
|
||||
padding-top: 20px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-resize"] {
|
||||
font-size: 22px !important;
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body offset="0" class="body" style="padding:0; margin:0; display:block; background:#f3f4f4; -webkit-text-size-adjust:none; " bgcolor="#EEEEEE">
|
||||
<table align="center" cellpadding="0" cellspacing="0" width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="top" style="background-color:#f3f4f4; " width="100%">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320">
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
|
||||
<!--Snippet Block-->
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="10" width="100%" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<table align="center" width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td align="right">
|
||||
<div style="display:none;font-size:1px;color:#333333;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">
|
||||
-
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Header Block-->
|
||||
<table bgcolor="#FFFFFF" border="0" cellspacing="0" cellpadding="0" align="center" width="100%"
|
||||
style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; border-bottom:solid 1px #dedee4; border-top:solid 1px #dedee4; width:100%!important; min-width:100%;">
|
||||
<tr style="width:100%;">
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="10" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="left" valign="middle"><a style="color: #ffffff; text-decoration: none;" href=
|
||||
"http://go.alfresco.com/a0100K050L0000KZjI2d00U" target="_blank"
|
||||
><span style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; color: #727174;"><img
|
||||
style="border:none; display:block; border-collapse:collapse; outline:none; text-decoration:none;"
|
||||
src="${template_assets_url}/Alfresco_Logo_gray.png" border="0"
|
||||
alt="Alfresco" width="122" height="38"></span></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td align="right" bgcolor="#FFFFFF">
|
||||
<table border="0" cellspacing="0" cellpadding="10" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="right" valign="middle"><span
|
||||
style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; font-weight:200; color: #727174;">make business flow</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Body Block 1-->
|
||||
<!--Banner Block-->
|
||||
<table cellspacing="0" cellpadding="0" width="100%" style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; ">
|
||||
<tr>
|
||||
<td style="border-collapse:collapse; ">
|
||||
<table cellspacing="0" cellpadding="0" width="100%" style="background-color:#0c79bf; border:none; ">
|
||||
<tr>
|
||||
<td style="border-collapse:collapse; ">
|
||||
<div class="mktEditable" id="Banner Image 1"><span
|
||||
style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; color: #ffffff;"><img
|
||||
src="${template_assets_url}/Product_Banner_1.jpg" alt="Alfresco Products" style="width:100%; border:none;
|
||||
display:block; border-collapse:collapse; outline:none; text-decoration:none;"></span></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--Copy-->
|
||||
<table cellspacing="0" cellpadding="0" align="center" bgcolor="#FFFFFF"
|
||||
style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; border-bottom:solid 1px #dedee4; " width="100%">
|
||||
<tr align="center">
|
||||
<td style="background-color:#ffffff; " align="center">
|
||||
<table class="force-width-80" cellspacing="0" cellpadding="12" align="center" bgcolor="#FFFFFF" width="80%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<!--Headline Text-->
|
||||
<div class="mktEditable" id="Headline Text 1" align="left" style="vertical-align:middle; "><span
|
||||
style="color: #727174; margin: 0px; font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 22px; font-weight: 600; text-align: left; text-decoration: none; vertical-align:
|
||||
middle;"><p>${message("templates.reset-password-email.ftl.title")}</p></span></div>
|
||||
<div class="mktEditable" id="Body Text 1" align="left">
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:18px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<p>${message("templates.reset-password-email.ftl.detail")}</p>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="5">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Button-->
|
||||
<table style="margin:0 auto; " cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align:center; margin:0 auto; ">
|
||||
<div><!--[if mso]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
style="height:45px;v-text-anchor:middle;width:220px;" stroke="f"
|
||||
fillcolor="#47AA2">
|
||||
<w:anchorlock/>
|
||||
<center>
|
||||
<![endif]-->
|
||||
<div class="mktEditable" id="Button Text"><a href="${reset_password_url}" style="background-color:#47aa42; color:#ffffff; display:inline-block; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:18px; font-weight:400; line-height:45px; text-align:center; text-decoration:none; width:220px;
|
||||
-webkit-text-size-adjust:none;">${message("templates.reset-password-email.ftl.reset_password_button")}</a></div>
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:12px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<p>${message("templates.reset-password-email.ftl.ignore_message")}</p>
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:12px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<hr>
|
||||
<p>${message("templates.reset-password-email.ftl.having_trouble_clicking_button")}</p>
|
||||
<p><a href="${reset_password_url}">${reset_password_url}</a></p>
|
||||
</span>
|
||||
<!--[if mso]>
|
||||
</center>
|
||||
</v:rect>
|
||||
<![endif]--></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="5">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Footer Block-->
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table cellspacing="0" cellpadding="0" border="0" align="center">
|
||||
<tr>
|
||||
<td cellspacing="0" cellpadding="0" border="0" align="center"><a
|
||||
style="color: #ffffff; text-decoration: none;"
|
||||
href="http://go.alfresco.com/a0100K060L0000RZeI2o00U" target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_Twitter.png" width="23" height="23"
|
||||
border="0"></a> <a style="color: #ffffff; text-decoration: none;"
|
||||
href="http://go.alfresco.com/G6I0Zo100S0fL0UK0000020"
|
||||
target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_LinkedIn.png" width="23" height="23" border="0"></a>
|
||||
<a style="color:
|
||||
#ffffff; text-decoration: none;" href="http://go.alfresco.com/TT2Lo00060000Ig10K00UZ0" target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_Facebook.png" width="23" height="23"
|
||||
border="0"></a> <a style="color: #ffffff; text-decoration: none;"
|
||||
href="http://go.alfresco.com/v00002oh0UKZL0U6I010000"
|
||||
target="_blank"><img
|
||||
src="${template_assets_url}/Alfresco_Icon_Social_Google.png" width="23" height="23"
|
||||
border="0"></a></td>
|
||||
<td cellspacing="0" cellpadding="0" border="0" align="center" width="10"></td>
|
||||
<td cellspacing="0" cellpadding="0" border="0" align="center"><a style="color: #333333;"
|
||||
href="http://go.alfresco.com/a0100K050L0000KZjI2d00U"
|
||||
target="_blank"><span
|
||||
style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #727174;"><img
|
||||
src="${template_assets_url}/AlfrescoGlobal_Logo_BW.png" border="0" alt="alfresco.com" width="92"
|
||||
height="29"><br></span></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a style="color: #0c79bf; text-decoration: underline;" href="http://www.alfresco.com/company/contact"
|
||||
target="_blank"><span
|
||||
style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #0c79bf;">${message("templates.generic-email.ftl.contact_us")}</span></a>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial,
|
||||
sans-serif; font-size: 10px; color: #b3b3b8;">© ${date?string["yyyy"]} Alfresco Software, Inc.
|
||||
${message("templates.generic-email.ftl.copy_right")}</span><br>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #b3b3b8;">Bridge Ave, The Place Maidenhead SL6 1AF United Kingdom</span><br>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #b3b3b8;">1825 S Grant St, Suite 900 San Mateo, CA 94402 USA</span><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--Litmus Tracking-->
|
||||
<table style="display: none;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 0px; display: none; overflow: hidden; max-height: 0px;">{{my.Litmus_Code}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
64
config/alfresco/workflow/reset-password-workflow-model.xml
Normal file
64
config/alfresco/workflow/reset-password-workflow-model.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Reset Password Workflow Model -->
|
||||
|
||||
<model name="resetpasswordwf:reset-password-workflow-model" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||
|
||||
<imports>
|
||||
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
|
||||
<import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm" />
|
||||
</imports>
|
||||
|
||||
<namespaces>
|
||||
<namespace uri="http://www.alfresco.org/model/workflow/resetpassword/1.0" prefix="resetpasswordwf" />
|
||||
</namespaces>
|
||||
|
||||
<types>
|
||||
<type name="resetpasswordwf:requestPasswordResetTask">
|
||||
<parent>bpm:startTask</parent>
|
||||
<mandatory-aspects>
|
||||
<aspect>resetpasswordwf:resetPasswordInitialProperties</aspect>
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
|
||||
<type name="resetpasswordwf:sendResetPasswordEmailTask">
|
||||
<parent>bpm:workflowTask</parent>
|
||||
<mandatory-aspects>
|
||||
<aspect>resetpasswordwf:resetPasswordInitialProperties</aspect>
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
|
||||
<type name="resetpasswordwf:resetPasswordTask">
|
||||
<parent>bpm:workflowTask</parent>
|
||||
<mandatory-aspects>
|
||||
<aspect>resetpasswordwf:resetPasswordInitialProperties</aspect>
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
|
||||
<type name="resetpasswordwf:performResetPassword">
|
||||
<parent>bpm:workflowTask</parent>
|
||||
<mandatory-aspects>
|
||||
<aspect>resetpasswordwf:resetPasswordInitialProperties</aspect>
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
</types>
|
||||
|
||||
<aspects>
|
||||
<aspect name="resetpasswordwf:resetPasswordInitialProperties">
|
||||
<properties>
|
||||
<property name="resetpasswordwf:userName">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="resetpasswordwf:userEmail">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="resetpasswordwf:key">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
<property name="resetpasswordwf:clientName">
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
</properties>
|
||||
</aspect>
|
||||
</aspects>
|
||||
</model>
|
@@ -0,0 +1,45 @@
|
||||
<?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:activiti="http://activiti.org/bpmn"
|
||||
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://alfresco.org">
|
||||
|
||||
<process isExecutable="true" id="resetPassword" name="On Premise Reset Password process">
|
||||
|
||||
<startEvent id="start" activiti:formKey="resetpasswordwf:requestPasswordResetTask"/>
|
||||
|
||||
<sequenceFlow id="flow1" sourceRef="start" targetRef="sendResetPasswordEmailTask"/>
|
||||
|
||||
<serviceTask id="sendResetPasswordEmailTask" name="Send Reset Password Email" activiti:delegateExpression="${SendResetPasswordEmailDelegate}"
|
||||
activiti:formKey="resetpasswordwf:sendResetPasswordEmailTask"/>
|
||||
|
||||
<sequenceFlow id="flow2" sourceRef="sendResetPasswordEmailTask" targetRef="resetPasswordTask"/>
|
||||
|
||||
<!-- The password reset has been requested and is now waiting for the user to complete by clicking on the link in the email. -->
|
||||
<!-- Note that we do not store the password as an execution variable for security reasons. -->
|
||||
<userTask id="resetPasswordTask" name="Password Reset Pending" activiti:formKey="resetpasswordwf:resetPasswordTask"/>
|
||||
|
||||
<!-- After 'system.reset-password.endTimer' of waiting for user to reset password, end the process -->
|
||||
<boundaryEvent id="endProcessTimer" cancelActivity="true" attachedToRef="resetPasswordTask">
|
||||
<timerEventDefinition>
|
||||
<timeDuration>${resetpasswordwf_endTimer}</timeDuration>
|
||||
</timerEventDefinition>
|
||||
</boundaryEvent>
|
||||
<sequenceFlow sourceRef="endProcessTimer" targetRef="expired"/>
|
||||
|
||||
<sequenceFlow sourceRef="resetPasswordTask" targetRef="performResetPassword"/>
|
||||
|
||||
<!-- The user has submitted the necessary data to reset the password. -->
|
||||
<serviceTask id="performResetPassword" name="Perform Reset Password" activiti:delegateExpression="${PerformResetPasswordDelegate}"
|
||||
activiti:formKey="resetpasswordwf:passwordReset"/>
|
||||
|
||||
<sequenceFlow sourceRef="performResetPassword" targetRef="end"/>
|
||||
|
||||
<endEvent id="end"/>
|
||||
<endEvent id="expired"/>
|
||||
</process>
|
||||
|
||||
</definitions>
|
@@ -146,3 +146,7 @@ workflowtask.outcome.Approve=Approved
|
||||
workflowtask.outcome.Reject=Rejected
|
||||
|
||||
workflowtask.already.done.error=This task has already been completed and is no longer editable.
|
||||
|
||||
# Reset password Task Definitions
|
||||
resetpasswordwf_resetpassword.resetpassword.workflow.title=Request Password Reset.
|
||||
resetpasswordwf_resetpassword.resetpassword.workflow.description=Used to request a password reset for a user's own login.
|
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import org.activiti.engine.delegate.DelegateExecution;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig.ClientApp;
|
||||
import org.alfresco.repo.client.config.ClientAppNotFoundException;
|
||||
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetPasswordDetails;
|
||||
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetPasswordEmailDetails;
|
||||
|
||||
/**
|
||||
* Reset password service.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public interface ResetPasswordService
|
||||
{
|
||||
/**
|
||||
* Request password reset (starts the workflow).
|
||||
*
|
||||
* @param userId the user id
|
||||
* @param clientName the client app name (used to lookup the client that is registered to send emails so that
|
||||
* client's specific configuration could be used.)
|
||||
*/
|
||||
void requestReset(String userId, String clientName);
|
||||
|
||||
/**
|
||||
* Validates the request reset password workflow and updates the workflow.
|
||||
*
|
||||
* @param resetDetails the {@code ResetPasswordDetails} object
|
||||
*/
|
||||
void resetPassword(ResetPasswordDetails resetDetails);
|
||||
|
||||
/**
|
||||
* Sends reset password email.
|
||||
*
|
||||
* @param execution the {@code DelegateExecution} object (is provided when a user requests password reset)
|
||||
* @param fallbackEmailTemplatePath the class path of the fallback email template (request reset password email)
|
||||
* @param emailSubject the email subject key
|
||||
*/
|
||||
void sendResetPasswordEmail(DelegateExecution execution, String fallbackEmailTemplatePath, String emailSubject);
|
||||
|
||||
/**
|
||||
* Updates the user's new password.
|
||||
*
|
||||
* @param execution the {@code DelegateExecution} object
|
||||
* @param fallbackEmailTemplatePath the class path of the fallback email template (confirmation email)
|
||||
* @param emailSubject the email subject key
|
||||
*/
|
||||
void performResetPassword(DelegateExecution execution, String fallbackEmailTemplatePath, String emailSubject);
|
||||
|
||||
/**
|
||||
* Sends an email.
|
||||
*
|
||||
* @param emailDetails the {@code ResetPasswordEmailDetails} object
|
||||
*/
|
||||
void sendEmail(ResetPasswordEmailDetails emailDetails);
|
||||
|
||||
/**
|
||||
* Gets the registered client.
|
||||
*
|
||||
* @param clientName the client name
|
||||
* @return {@code ClientApp} object
|
||||
* @throws ClientAppNotFoundException if no {@code ClientApp} is found with the given name
|
||||
*/
|
||||
ClientApp getClientAppConfig(String clientName);
|
||||
}
|
@@ -0,0 +1,776 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import org.activiti.engine.HistoryService;
|
||||
import org.activiti.engine.TaskService;
|
||||
import org.activiti.engine.delegate.DelegateExecution;
|
||||
import org.activiti.engine.task.Task;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.executer.MailActionExecuter;
|
||||
import org.alfresco.repo.admin.SysAdminParams;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig.ClientApp;
|
||||
import org.alfresco.repo.client.config.ClientAppNotFoundException;
|
||||
import org.alfresco.repo.workflow.BPMEngineRegistry;
|
||||
import org.alfresco.repo.workflow.WorkflowModel;
|
||||
import org.alfresco.repo.workflow.WorkflowModelResetPassword;
|
||||
import org.alfresco.repo.workflow.activiti.ActivitiConstants;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowInstance;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowPath;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTask;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowTaskQuery;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EmailHelper;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.UrlUtil;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Reset password implementation based on workflow.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(ResetPasswordServiceImpl.class);
|
||||
|
||||
private static final String TIMER_END = "PT1H";
|
||||
private static final String WORKFLOW_DESCRIPTION_KEY = "resetpasswordwf_resetpassword.resetpassword.workflow.description";
|
||||
private static final String FTL_TEMPLATE_ASSETS_URL = "template_assets_url";
|
||||
private static final String FTL_RESET_PASSWORD_URL = "reset_password_url";
|
||||
private static final String FTL_USER_NAME = "userName";
|
||||
|
||||
private WorkflowService workflowService;
|
||||
private HistoryService activitiHistoryService;
|
||||
private ActionService actionService;
|
||||
private PersonService personService;
|
||||
private NodeService nodeService;
|
||||
private SysAdminParams sysAdminParams;
|
||||
private MutableAuthenticationService authenticationService;
|
||||
private TaskService activitiTaskService;
|
||||
private EmailHelper emailHelper;
|
||||
private ClientAppConfig clientAppConfig;
|
||||
private String timerEnd = TIMER_END;
|
||||
private String defaultEmailSender;
|
||||
|
||||
public void setWorkflowService(WorkflowService workflowService)
|
||||
{
|
||||
this.workflowService = workflowService;
|
||||
}
|
||||
|
||||
public void setActivitiHistoryService(HistoryService activitiHistoryService)
|
||||
{
|
||||
this.activitiHistoryService = activitiHistoryService;
|
||||
}
|
||||
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
public void setPersonService(PersonService personService)
|
||||
{
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setSysAdminParams(SysAdminParams sysAdminParams)
|
||||
{
|
||||
this.sysAdminParams = sysAdminParams;
|
||||
}
|
||||
|
||||
public void setAuthenticationService(MutableAuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
public void setActivitiTaskService(TaskService activitiTaskService)
|
||||
{
|
||||
this.activitiTaskService = activitiTaskService;
|
||||
}
|
||||
|
||||
public void setEmailHelper(EmailHelper emailHelper)
|
||||
{
|
||||
this.emailHelper = emailHelper;
|
||||
}
|
||||
|
||||
public void setClientAppConfig(ClientAppConfig clientAppConfig)
|
||||
{
|
||||
this.clientAppConfig = clientAppConfig;
|
||||
}
|
||||
|
||||
public void setTimerEnd(String timerEnd)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(timerEnd))
|
||||
{
|
||||
this.timerEnd = timerEnd;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultEmailSender(String defaultEmailSender)
|
||||
{
|
||||
this.defaultEmailSender = defaultEmailSender;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "workflowService", workflowService);
|
||||
PropertyCheck.mandatory(this, "activitiHistoryService", activitiHistoryService);
|
||||
PropertyCheck.mandatory(this, "actionService", actionService);
|
||||
PropertyCheck.mandatory(this, "personService", personService);
|
||||
PropertyCheck.mandatory(this, "nodeService", nodeService);
|
||||
PropertyCheck.mandatory(this, "sysAdminParams", sysAdminParams);
|
||||
PropertyCheck.mandatory(this, "authenticationService", authenticationService);
|
||||
PropertyCheck.mandatory(this, "activitiTaskService", activitiTaskService);
|
||||
PropertyCheck.mandatory(this, "emailHelper", emailHelper);
|
||||
PropertyCheck.mandatory(this, "clientAppConfig", clientAppConfig);
|
||||
PropertyCheck.mandatory(this, "defaultEmailSender", defaultEmailSender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestReset(String userId, String clientName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("userId", userId);
|
||||
ParameterCheck.mandatoryString("clientName", clientName);
|
||||
|
||||
String userEmail = validateUserAndGetEmail(userId);
|
||||
|
||||
// Get the (latest) workflow definition for reset-password.
|
||||
WorkflowDefinition wfDefinition = workflowService.getDefinitionByName(WorkflowModelResetPassword.WORKFLOW_DEFINITION_NAME);
|
||||
|
||||
// create workflow properties
|
||||
Map<QName, Serializable> props = new HashMap<>(7);
|
||||
props.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, I18NUtil.getMessage(WORKFLOW_DESCRIPTION_KEY));
|
||||
props.put(WorkflowModelResetPassword.WF_PROP_USERNAME, userId);
|
||||
props.put(WorkflowModelResetPassword.WF_PROP_USER_EMAIL, userEmail);
|
||||
props.put(WorkflowModelResetPassword.WF_PROP_CLIENT_NAME, clientName);
|
||||
props.put(WorkflowModel.ASSOC_PACKAGE, workflowService.createPackage(null));
|
||||
|
||||
String guid = GUID.generate();
|
||||
props.put(WorkflowModelResetPassword.WF_PROP_KEY, guid);
|
||||
props.put(WorkflowModelResetPassword.WF_PROP_TIMER_END, timerEnd);
|
||||
|
||||
// start the workflow
|
||||
WorkflowPath path = workflowService.startWorkflow(wfDefinition.getId(), props);
|
||||
if (path.isActive())
|
||||
{
|
||||
WorkflowTask startTask = workflowService.getStartTask(path.getInstance().getId());
|
||||
workflowService.endTask(startTask.getId(), null);
|
||||
}
|
||||
}
|
||||
|
||||
protected String validateUserAndGetEmail(String userId)
|
||||
{
|
||||
if (!personService.personExists(userId))
|
||||
{
|
||||
throw new ResetPasswordWorkflowInvalidUserException("User does not exist: " + userId);
|
||||
}
|
||||
else if (!personService.isEnabled(userId))
|
||||
{
|
||||
throw new ResetPasswordWorkflowInvalidUserException("User is disabled: " + userId);
|
||||
}
|
||||
|
||||
NodeRef personNode = personService.getPerson(userId, false);
|
||||
return (String) nodeService.getProperty(personNode, ContentModel.PROP_EMAIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(ResetPasswordDetails resetDetails)
|
||||
{
|
||||
ParameterCheck.mandatory("resetDetails", resetDetails);
|
||||
|
||||
validateIdAndKey(resetDetails.getWorkflowId(), resetDetails.getWorkflowKey(), resetDetails.getUserId());
|
||||
|
||||
// So now we know that the workflow instance exists, is active and has the correct key. We can proceed.
|
||||
WorkflowTaskQuery processTaskQuery = new WorkflowTaskQuery();
|
||||
processTaskQuery.setProcessId(resetDetails.getWorkflowId());
|
||||
List<WorkflowTask> tasks = workflowService.queryTasks(processTaskQuery, false);
|
||||
|
||||
if (tasks.isEmpty())
|
||||
{
|
||||
throw new InvalidResetPasswordWorkflowException(
|
||||
"Invalid workflow identifier: " + resetDetails.getWorkflowId() + ", " + resetDetails.getWorkflowKey());
|
||||
}
|
||||
WorkflowTask task = tasks.get(0);
|
||||
|
||||
// Set the provided password into the task. We will remove this after we have updated the user's authentication details.
|
||||
Map<QName, Serializable> props = Collections.singletonMap(WorkflowModelResetPassword.WF_PROP_PASSWORD, resetDetails.getPassword());
|
||||
|
||||
// Note the taskId as taken from the WorkflowService will include a "activiti$" prefix.
|
||||
final String taskId = task.getId();
|
||||
workflowService.updateTask(taskId, props, null, null);
|
||||
workflowService.endTask(taskId, null);
|
||||
|
||||
// Remove the previous task from Activiti's history - so that the password will not be in the database.
|
||||
// See http://www.activiti.org/userguide/index.html#history for a description of how Activiti stores historical records of
|
||||
// processes, tasks and properties.
|
||||
// The activitiHistoryService does not expect the activiti$ prefix.
|
||||
final String activitiTaskId = taskId.replace("activiti$", "");
|
||||
activitiHistoryService.deleteHistoricTaskInstance(activitiTaskId);
|
||||
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Deleting historical task for security reasons " + activitiTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method ensures that the id refers to an in-progress workflow and that the key matches
|
||||
* that stored in the workflow.
|
||||
*
|
||||
* @throws WebScriptException a 404 if any of the above is not true.
|
||||
*/
|
||||
private void validateIdAndKey(String id, String key, String userId)
|
||||
{
|
||||
WorkflowInstance workflowInstance = null;
|
||||
try
|
||||
{
|
||||
workflowInstance = workflowService.getWorkflowById(id);
|
||||
}
|
||||
catch (WorkflowException ignored)
|
||||
{
|
||||
// Intentionally empty.
|
||||
}
|
||||
|
||||
if (workflowInstance == null)
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("The reset password workflow instance with the id [" + id + "] is not found.");
|
||||
}
|
||||
throw new ResetPasswordWorkflowNotFoundException("Reset Password cannot be linked to an ongoing secure process.");
|
||||
}
|
||||
|
||||
String recoveredKey;
|
||||
String username;
|
||||
if (workflowInstance.isActive())
|
||||
{
|
||||
// If the workflow is active we will be able to read the path properties.
|
||||
Map<QName, Serializable> pathProps = workflowService.getPathProperties(id);
|
||||
|
||||
username = (String) pathProps.get(WorkflowModelResetPassword.WF_PROP_USERNAME);
|
||||
recoveredKey = (String) pathProps.get(WorkflowModelResetPassword.WF_PROP_KEY);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("The reset password workflow instance with the id [" + id + "] is not active.");
|
||||
}
|
||||
throw new InvalidResetPasswordWorkflowException("Reset Password cannot be linked to an ongoing secure process.");
|
||||
}
|
||||
if (username == null || recoveredKey == null || !recoveredKey.equals(key))
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
if (username == null)
|
||||
{
|
||||
LOGGER.debug("The recovered user name is null for the reset password workflow instance with the id [" + id + "]");
|
||||
}
|
||||
else if (recoveredKey == null)
|
||||
{
|
||||
LOGGER.debug("The recovered key is null for the reset password workflow instance with the id [" + id + "]");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.debug("The recovered key [" + recoveredKey + "] does not match the given workflow key [" + key
|
||||
+ "] for the reset password workflow instance with the id [" + id + "]");
|
||||
}
|
||||
}
|
||||
throw new InvalidResetPasswordWorkflowException("Reset Password cannot be linked to an ongoing secure process.");
|
||||
}
|
||||
else if (!username.equals(userId))
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("The given user id [" + userId + "] does not match the person's user id [" + username
|
||||
+ "] who requested the password reset.");
|
||||
}
|
||||
throw new InvalidResetPasswordWorkflowException("Reset Password cannot be linked to an ongoing secure process.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientApp getClientAppConfig(String clientName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("clientName", clientName);
|
||||
|
||||
ClientApp clientApp = clientAppConfig.getClient(clientName);
|
||||
if (clientApp == null)
|
||||
{
|
||||
throw new ClientAppNotFoundException("Client was not found [" + clientName + "]");
|
||||
}
|
||||
return clientApp;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sendResetPasswordEmail(DelegateExecution execution, String fallbackEmailTemplatePath, String emailSubject)
|
||||
{
|
||||
Map<String, Object> variables = execution.getVariables();
|
||||
final String userName = (String) variables.get(WorkflowModelResetPassword.WF_PROP_USERNAME_ACTIVITI);
|
||||
final String toEmail = (String) variables.get(WorkflowModelResetPassword.WF_PROP_USER_EMAIL_ACTIVITI);
|
||||
final String clientName = (String) variables.get(WorkflowModelResetPassword.WF_PROP_CLIENT_NAME_ACTIVITI);
|
||||
final String key = (String) variables.get(WorkflowModelResetPassword.WF_PROP_KEY_ACTIVITI);
|
||||
final String id = execution.getProcessInstanceId();
|
||||
|
||||
final ClientApp clientApp = getClientAppConfig(clientName);
|
||||
Map<String, Serializable> emailTemplateModel = Collections.singletonMap(FTL_RESET_PASSWORD_URL,
|
||||
createResetPasswordUrl(clientApp, id, key));
|
||||
|
||||
final String templatePath = emailHelper.getEmailTemplate(clientName,
|
||||
getResetPasswordEmailTemplate(clientApp),
|
||||
fallbackEmailTemplatePath);
|
||||
|
||||
ResetPasswordEmailDetails emailRequest = new ResetPasswordEmailDetails()
|
||||
.setUserName(userName)
|
||||
.setUserEmail(toEmail)
|
||||
.setTemplatePath(templatePath)
|
||||
.setTemplateAssetsUrl(clientApp.getTemplateAssetsUrl())
|
||||
.setEmailSubject(emailSubject)
|
||||
.setTemplateModel(emailTemplateModel);
|
||||
|
||||
sendEmail(emailRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performResetPassword(DelegateExecution execution, String fallbackEmailTemplatePath, String emailSubject)
|
||||
{
|
||||
// This method chooses to take a rather indirect route to access the password value.
|
||||
// This is for security reasons. We do not want to store the password in the Activiti DB.
|
||||
|
||||
// We can get the username from the execution (process scope).
|
||||
Map<String, Object> variables = execution.getVariables();
|
||||
final String userName = (String) variables.get(WorkflowModelResetPassword.WF_PROP_USERNAME_ACTIVITI);
|
||||
final String userEmail = (String) variables.get(WorkflowModelResetPassword.WF_PROP_USER_EMAIL_ACTIVITI);
|
||||
final String clientName = (String) variables.get(WorkflowModelResetPassword.WF_PROP_CLIENT_NAME_ACTIVITI);
|
||||
|
||||
// But we cannot get the password from the execution as we have intentionally not stored the password there.
|
||||
// Instead we recover the password from the specific task in which it was set.
|
||||
List<Task> activitiTasks = activitiTaskService.createTaskQuery().taskDefinitionKey(WorkflowModelResetPassword.TASK_RESET_PASSWORD)
|
||||
.processInstanceId(execution.getProcessInstanceId()).list();
|
||||
if (activitiTasks.size() != 1)
|
||||
{
|
||||
throw new ResetPasswordWorkflowException("Unexpected count of task instances: " + activitiTasks.size());
|
||||
}
|
||||
Task activitiTask = activitiTasks.get(0);
|
||||
String activitiTaskId = activitiTask.getId();
|
||||
final String password = (String) activitiTaskService.getVariable(activitiTaskId, WorkflowModelResetPassword.WF_PROP_PASSWORD_ACTIVITI);
|
||||
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Retrieved new password from task " + activitiTaskId);
|
||||
}
|
||||
|
||||
ParameterCheck.mandatoryString(WorkflowModelResetPassword.WF_PROP_USERNAME_ACTIVITI, userName);
|
||||
ParameterCheck.mandatoryString(WorkflowModelResetPassword.WF_PROP_PASSWORD_ACTIVITI, password);
|
||||
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Changing password for " + userName);
|
||||
// Don't LOG the password. :)
|
||||
}
|
||||
|
||||
this.authenticationService.setAuthentication(userName, password.toCharArray());
|
||||
|
||||
// Now notify the user
|
||||
final ClientApp clientApp = getClientAppConfig(clientName);
|
||||
Map<String, Serializable> emailTemplateModel = Collections.singletonMap(FTL_USER_NAME, userName);
|
||||
|
||||
final String templatePath = emailHelper.getEmailTemplate(clientName,
|
||||
getConfirmResetPasswordEmailTemplate(clientApp),
|
||||
fallbackEmailTemplatePath);
|
||||
|
||||
ResetPasswordEmailDetails emailRequest = new ResetPasswordEmailDetails()
|
||||
.setUserName(userName)
|
||||
.setUserEmail(userEmail)
|
||||
.setTemplatePath(templatePath)
|
||||
.setTemplateAssetsUrl(clientApp.getTemplateAssetsUrl())
|
||||
.setEmailSubject(emailSubject)
|
||||
.setTemplateModel(emailTemplateModel);
|
||||
|
||||
sendEmail(emailRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmail(ResetPasswordEmailDetails emailRequest)
|
||||
{
|
||||
// Prepare the email
|
||||
Map<String, Serializable> templateModel = new HashMap<>();
|
||||
// Replace '${shareUrl}' placeholder if it does exist.
|
||||
final String templateAssetsUrl = getUrl(emailRequest.getTemplateAssetsUrl(), ClientAppConfig.PROP_TEMPLATE_ASSETS_URL);
|
||||
templateModel.put(FTL_TEMPLATE_ASSETS_URL, templateAssetsUrl);
|
||||
if (emailRequest.getTemplateModel() != null)
|
||||
{
|
||||
templateModel.putAll(emailRequest.getTemplateModel());
|
||||
}
|
||||
|
||||
Map<String, Serializable> actionParams = new HashMap<>(8);
|
||||
String fromEmail = emailRequest.getFromEmail();
|
||||
if(StringUtils.isEmpty(fromEmail))
|
||||
{
|
||||
fromEmail = this.defaultEmailSender;
|
||||
}
|
||||
actionParams.put(MailActionExecuter.PARAM_FROM, fromEmail);
|
||||
actionParams.put(MailActionExecuter.PARAM_TO, emailRequest.getUserEmail());
|
||||
actionParams.put(MailActionExecuter.PARAM_SUBJECT, emailRequest.getEmailSubject());
|
||||
// Pick the template
|
||||
actionParams.put(MailActionExecuter.PARAM_TEMPLATE, emailRequest.getTemplatePath());
|
||||
actionParams.put(MailActionExecuter.PARAM_TEMPLATE_MODEL, (Serializable) templateModel);
|
||||
|
||||
final Locale locale = emailHelper.getUserLocaleOrDefault(emailRequest.getUserName());
|
||||
actionParams.put(MailActionExecuter.PARAM_LOCALE, locale);
|
||||
|
||||
actionParams.put(MailActionExecuter.PARAM_IGNORE_SEND_FAILURE, true);
|
||||
actionParams.put(MailActionExecuter.PARAM_IGNORE_SEND_FAILURE, emailRequest.ignoreSendFailure);
|
||||
// Now send the email
|
||||
Action mailAction = actionService.createAction(MailActionExecuter.NAME, actionParams);
|
||||
actionService.executeAction(mailAction, null, false, true);
|
||||
}
|
||||
|
||||
private String getUrl(String url, String propName)
|
||||
{
|
||||
if (url == null)
|
||||
{
|
||||
LOGGER.warn("The url for the property [" + propName + "] is not configured.");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (url.endsWith("/"))
|
||||
{
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
return UrlUtil.replaceShareUrlPlaceholder(url, sysAdminParams);
|
||||
}
|
||||
|
||||
protected String getResetPasswordEmailTemplate(ClientApp clientApp)
|
||||
{
|
||||
return clientApp.getProperty("requestResetPasswordTemplatePath");
|
||||
}
|
||||
|
||||
protected String getConfirmResetPasswordEmailTemplate(ClientApp clientApp)
|
||||
{
|
||||
return clientApp.getProperty("confirmResetPasswordTemplatePath");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a URL for the 'reset password' link which appears in the email
|
||||
*/
|
||||
protected String createResetPasswordUrl(ClientApp clientApp, final String id, final String key)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
|
||||
String pageUrl = clientApp.getProperty("resetPasswordPageUrl");
|
||||
if (StringUtils.isEmpty(pageUrl))
|
||||
{
|
||||
sb.append(UrlUtil.getShareUrl(sysAdminParams));
|
||||
|
||||
LOGGER.warn("'resetPasswordPageUrl' property is not set for the client [" + clientApp.getName()
|
||||
+ "]. The default base url of Share will be used [" + sb.toString() + "]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// We pass an empty string as we know that the pageUrl is not null
|
||||
sb.append(getUrl(pageUrl, ""));
|
||||
}
|
||||
|
||||
sb.append("?key=").append(key)
|
||||
.append("&id=").append(BPMEngineRegistry.createGlobalId(ActivitiConstants.ENGINE_ID, id));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public static class ResetPasswordDetails
|
||||
{
|
||||
private String userId;
|
||||
private String password;
|
||||
private String workflowId;
|
||||
private String workflowKey;
|
||||
|
||||
public String getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
public ResetPasswordDetails setUserId(String userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public ResetPasswordDetails setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getWorkflowId()
|
||||
{
|
||||
return workflowId;
|
||||
}
|
||||
|
||||
public ResetPasswordDetails setWorkflowId(String workflowId)
|
||||
{
|
||||
this.workflowId = workflowId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getWorkflowKey()
|
||||
{
|
||||
return workflowKey;
|
||||
}
|
||||
|
||||
public ResetPasswordDetails setWorkflowKey(String workflowKey)
|
||||
{
|
||||
this.workflowKey = workflowKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder(100);
|
||||
sb.append("ResetPasswordDetails [userId=").append(userId)
|
||||
.append(", workflowId=").append(workflowId)
|
||||
.append(", workflowKey=").append(workflowKey)
|
||||
.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public static class ResetPasswordEmailDetails
|
||||
{
|
||||
private String userName;
|
||||
private String userEmail;
|
||||
private String fromEmail;
|
||||
private String templatePath;
|
||||
private String templateAssetsUrl;
|
||||
private Map<String, Serializable> templateModel;
|
||||
private String emailSubject;
|
||||
private boolean ignoreSendFailure = true;
|
||||
|
||||
public String getUserName()
|
||||
{
|
||||
return userName;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setUserName(String userName)
|
||||
{
|
||||
this.userName = userName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUserEmail()
|
||||
{
|
||||
return userEmail;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setUserEmail(String userEmail)
|
||||
{
|
||||
this.userEmail = userEmail;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getFromEmail()
|
||||
{
|
||||
return fromEmail;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setFromEmail(String fromEmail)
|
||||
{
|
||||
this.fromEmail = fromEmail;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTemplatePath()
|
||||
{
|
||||
return templatePath;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setTemplatePath(String templatePath)
|
||||
{
|
||||
this.templatePath = templatePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTemplateAssetsUrl()
|
||||
{
|
||||
return templateAssetsUrl;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setTemplateAssetsUrl(String templateAssetsUrl)
|
||||
{
|
||||
this.templateAssetsUrl = templateAssetsUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, Serializable> getTemplateModel()
|
||||
{
|
||||
return templateModel;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setTemplateModel(Map<String, Serializable> templateModel)
|
||||
{
|
||||
this.templateModel = templateModel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getEmailSubject()
|
||||
{
|
||||
return emailSubject;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setEmailSubject(String emailSubject)
|
||||
{
|
||||
this.emailSubject = emailSubject;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isIgnoreSendFailure()
|
||||
{
|
||||
return ignoreSendFailure;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setIgnoreSendFailure(boolean ignoreSendFailure)
|
||||
{
|
||||
this.ignoreSendFailure = ignoreSendFailure;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder(250);
|
||||
sb.append("ResetPasswordEmailDetails [userName=").append(userName)
|
||||
.append(", userEmail=").append(userEmail)
|
||||
.append(", fromEmail=").append(fromEmail)
|
||||
.append(", templatePath=").append(templatePath)
|
||||
.append(", templateAssetsUrl=").append(templateAssetsUrl)
|
||||
.append(", templateModel=").append(templateModel)
|
||||
.append(", emailSubject=").append(emailSubject)
|
||||
.append(", ignoreSendFailure=").append(ignoreSendFailure)
|
||||
.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public static class ResetPasswordWorkflowException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -694208478609278943L;
|
||||
|
||||
public ResetPasswordWorkflowException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public static class ResetPasswordWorkflowNotFoundException extends ResetPasswordWorkflowException
|
||||
{
|
||||
private static final long serialVersionUID = -7492264073778098895L;
|
||||
|
||||
public ResetPasswordWorkflowNotFoundException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public static class InvalidResetPasswordWorkflowException extends ResetPasswordWorkflowException
|
||||
{
|
||||
private static final long serialVersionUID = -4685359036247580984L;
|
||||
|
||||
public InvalidResetPasswordWorkflowException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public static class ResetPasswordWorkflowInvalidUserException extends ResetPasswordWorkflowException
|
||||
{
|
||||
private static final long serialVersionUID = -6524046975575636256L;
|
||||
|
||||
public ResetPasswordWorkflowInvalidUserException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.security.authentication.activiti;
|
||||
|
||||
import org.alfresco.repo.security.authentication.ResetPasswordService;
|
||||
import org.alfresco.repo.workflow.activiti.BaseJavaDelegate;
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public abstract class AbstractResetPasswordDelegate extends BaseJavaDelegate
|
||||
{
|
||||
protected ResetPasswordService resetPasswordService;
|
||||
|
||||
public void setResetPasswordService(ResetPasswordService resetPasswordService)
|
||||
{
|
||||
this.resetPasswordService = resetPasswordService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.security.authentication.activiti;
|
||||
|
||||
import org.activiti.engine.delegate.DelegateExecution;
|
||||
import org.activiti.engine.delegate.JavaDelegate;
|
||||
|
||||
/**
|
||||
* This {@link JavaDelegate activiti delegate} is executed when a user resets his/her password.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public class PerformResetPasswordDelegate extends AbstractResetPasswordDelegate
|
||||
{
|
||||
private static final String EMAIL_SUBJECT_KEY = "reset-password-confirmation.email.subject";
|
||||
private static final String EMAIL_TEMPLATE_PATH = "alfresco/templates/reset-password-email-templates/reset-password-confirmation-email-template.ftl";
|
||||
|
||||
@Override
|
||||
public void execute(DelegateExecution execution) throws Exception
|
||||
{
|
||||
resetPasswordService.performResetPassword(execution, EMAIL_TEMPLATE_PATH, EMAIL_SUBJECT_KEY);
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.security.authentication.activiti;
|
||||
|
||||
import org.activiti.engine.delegate.DelegateExecution;
|
||||
import org.activiti.engine.delegate.JavaDelegate;
|
||||
|
||||
/**
|
||||
* This {@link JavaDelegate activiti delegate} is executed when a user request password reset.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public class SendResetPasswordEmailDelegate extends AbstractResetPasswordDelegate
|
||||
{
|
||||
private static final String EMAIL_SUBJECT_KEY = "reset-password-request.email.subject";
|
||||
private static final String EMAIL_TEMPLATE_PATH = "alfresco/templates/reset-password-email-templates/reset-password-email-template.ftl";
|
||||
|
||||
@Override
|
||||
public void execute(DelegateExecution execution) throws Exception
|
||||
{
|
||||
resetPasswordService.sendResetPasswordEmail(execution, EMAIL_TEMPLATE_PATH, EMAIL_SUBJECT_KEY);
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.workflow;
|
||||
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public interface WorkflowModelResetPassword
|
||||
{
|
||||
// namespace
|
||||
String NAMESPACE_URI = "http://www.alfresco.org/model/workflow/resetpassword/1.0";
|
||||
|
||||
// process name
|
||||
String WORKFLOW_DEFINITION_NAME = "activiti$resetPassword";
|
||||
|
||||
// task names
|
||||
String TASK_RESET_PASSWORD = "resetPasswordTask";
|
||||
|
||||
// timers
|
||||
QName WF_PROP_TIMER_END = QName.createQName(NAMESPACE_URI, "endTimer");
|
||||
|
||||
// workflow properties
|
||||
QName WF_PROP_USERNAME = QName.createQName(NAMESPACE_URI, "userName");
|
||||
QName WF_PROP_USER_EMAIL = QName.createQName(NAMESPACE_URI, "userEmail");
|
||||
QName WF_PROP_KEY = QName.createQName(NAMESPACE_URI, "key");
|
||||
QName WF_PROP_PASSWORD = QName.createQName(NAMESPACE_URI, "password");
|
||||
QName WF_PROP_CLIENT_NAME = QName.createQName(NAMESPACE_URI, "clientName");
|
||||
|
||||
// workflow execution context variable names
|
||||
String WF_PROP_USERNAME_ACTIVITI = "resetpasswordwf_userName";
|
||||
String WF_PROP_USER_EMAIL_ACTIVITI = "resetpasswordwf_userEmail";
|
||||
String WF_PROP_KEY_ACTIVITI = "resetpasswordwf_key";
|
||||
String WF_PROP_PASSWORD_ACTIVITI = "resetpasswordwf_password";
|
||||
String WF_PROP_CLIENT_NAME_ACTIVITI = "resetpasswordwf_clientName";
|
||||
}
|
Reference in New Issue
Block a user