Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

License validation of a paid via atlassian plugin requires administration rights?

Tobias Reibling
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
July 30, 2012

Hi,

after getting the license validation working in our plugin (paid via atlassian), we suddenly were confronted with the fact that the way the license tutorial does the validation checks is not useable if the logged-in user has no administration rights.

Based on the LicenseHelloWorldServlet generated by the license module, I am supposed to check for a valid license like this:

try
        {
            //Check and see if a license is currently stored.
            //This accessor method can be used whether or not a licensing-aware UPM is present.
            if (licenseManager.getLicense().isDefined())
            {
                PluginLicense pluginLicense = licenseManager.getLicense().get();
                //Check and see if the stored license has an error. If not, it is currently valid.
                if (pluginLicense.getError().isDefined())
                {
                    //A license is currently stored, however, it is invalid (e.g. expired or user count mismatch)
                    resp.getWriter().write("I'd love to say hello, but cannot do so because your license has an error: " 
                            + pluginLicense.getError().get().name());
                }
                else
                {
                    //A license is currently stored and it is valid.
                    resp.getWriter().write("Hello, world! You are licensed!");
                }
            }
            else
            {
                //No license (valid or invalid) is stored.
                resp.getWriter().write("I'd love to say hello, but cannot do so because you don't have a license.");
            }
        }
        catch (PluginLicenseStoragePluginUnresolvedException e)
        {
            //The current license status cannot be retrieved because the Plugin License Storage plugin is unavailable.
            resp.getWriter().write("I'd love to say hello, but cannot find my required resources. Please speak to a system administrator.");
        }

The servlet quotes that this is how to ensure plugin license existence/validity at a plugin entry point. So I took this check and basically implemented it at every possible entry point in our plugin, which means every WebAction and so on.

As long as I was logged in as an administrator everything was working like a charm, but as soon as someone without administration rights logs in, the above code isnt able to retrieve the license and validate it because of missing rights.

So how am I supposed to ensure a constant validation of the current license at every time, no matter what user is logged in when the license manager isnt able to validate anything without administration rights? I dont think I am enforced to only check the license once if an administrator is logged in and never check it on other users. Is there any tutorial or something that shows some common practice on the correct validation of the license in every moment with the ThirdPartyLicenseStorageManager?

The only solution I am aware of at the moment is to check the license if an administrator logs in and save it in some way to be able to validate it again later when a non-administrator logs in and tries to use our plugin. Is this the correct way?

Thank you!

2 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

0 votes
Answer accepted
Tobias Reibling
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
July 31, 2012

Thanks again for your quick answer, this is the stacktrace which was generated:

com.atlassian.upm.license.storage.lib.PluginLicenseStoragePluginPermissionDeniedException: User 'michael' attempted an unpermitted license action.
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.execute(ThirdPartyPluginLicenseStorageManagerImpl.java:238)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.getLicense(ThirdPartyPluginLicenseStorageManagerImpl.java:72)
        at de.iconcept.ictime.managers.DefaultICTimeLicenseManager.validateLicense(DefaultICTimeLicenseManager.java:55)
        at de.iconcept.ictime.managers.DefaultICTimeLicenseManager.validLicenseExists(DefaultICTimeLicenseManager.java:101)
        at de.iconcept.ictime.actions.timeentry.ICTimeTrackingContextProvider.getContextMap(ICTimeTrackingContextProvider.java:163)
        at com.atlassian.jira.plugin.webfragment.contextproviders.AbstractJiraContextProvider.getContextMap(AbstractJiraContextProvider.java:32)
        at com.atlassian.plugin.web.model.AbstractWebItem.getContextMap(AbstractWebItem.java:30)
        at com.atlassian.plugin.web.model.DefaultWebLabel.getDisplayableLabel(DefaultWebLabel.java:55)
        at com.atlassian.jira.web.component.ModuleWebComponentImpl.renderModHeading(ModuleWebComponentImpl.java:310)
        at com.atlassian.jira.web.component.ModuleWebComponentImpl.renderModule(ModuleWebComponentImpl.java:167)
        at com.atlassian.jira.web.component.ModuleWebComponentImpl.renderModuleAndLetNoThrowablesEscape(ModuleWebComponentImpl.java:67)
        at com.atlassian.jira.web.component.ModuleWebComponentImpl.renderModules(ModuleWebComponentImpl.java:45)
        at com.atlassian.jira.issue.util.IssueWebPanelRenderUtil.renderPanels(IssueWebPanelRenderUtil.java:80)  <+2> (DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at webwork.util.InjectionUtils$DefaultInjectionImpl.invoke(InjectionUtils.java:70)
        at webwork.util.InjectionUtils.invoke(InjectionUtils.java:56)
        at webwork.util.ValueStack.findValue(ValueStack.java:514)
        at webwork.util.ValueStack.findValue(ValueStack.java:213)
        at webwork.view.taglib.WebWorkBodyTagSupport.findValue(WebWorkBodyTagSupport.java:62)
        at webwork.view.taglib.BasicPropertyTag.doStartTag(BasicPropertyTag.java:54)
        at org.apache.jsp.secure.views.issue.viewissue_jsp._jspx_meth_ww_005fproperty_005f6(viewissue_jsp.java:607)
        at org.apache.jsp.secure.views.issue.viewissue_jsp._jspx_meth_ww_005fproperty_005f5(viewissue_jsp.java:575)
        at org.apache.jsp.secure.views.issue.viewissue_jsp._jspService(viewissue_jsp.java:169)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:386)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  <+4> (ApplicationFilterChain.java:290) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:30)  <+46> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SiteMeshFilter.java:59) (SitemeshPageFilter.java:124) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SecurityFilter.java:82) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (BaseLoginFilter.java:157) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:71) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ApplicationDispatcher.java:646) (ApplicationDispatcher.java:436) (ApplicationDispatcher.java:374) (ApplicationDispatcher.java:302) (JiraWebworkActionDispatcher.java:314) (JiraWebworkActionDispatcher.java:205)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  <+4> (ApplicationFilterChain.java:290) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:30)  <+40> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SecurityFilter.java:82) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (BaseLoginFilter.java:157) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:71) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ApplicationDispatcher.java:646) (ApplicationDispatcher.java:436) (ApplicationDispatcher.java:374) (ApplicationDispatcher.java:302)
        at com.atlassian.jira.servlet.QuickLinkServlet.linkToIssue(QuickLinkServlet.java:158)
        at com.atlassian.jira.servlet.QuickLinkServlet.service(QuickLinkServlet.java:46)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  <+10> (ApplicationFilterChain.java:290) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (HeaderSanitisingFilter.java:44) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:36)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
        at com.atlassian.jira.tzdetect.IncludeResourcesFilter.doFilter(IncludeResourcesFilter.java:39)  <+24> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AccessLogFilter.java:103) (AccessLogFilter.java:87) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (XsrfTokenAdditionRequestFilter.java:54) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SiteMeshFilter.java:129) (SiteMeshFilter.java:77) (SitemeshPageFilter.java:124) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.remoteapps.modules.permissions.ApiScopingFilter.doFilter(ApiScopingFilter.java:71)  <+41> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SecurityFilter.java:234) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (TrustedApplicationsFilter.java:98) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (BaseLoginFilter.java:157) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:71) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ProfilingFilter.java:99) (JIRAProfilingFilter.java:19) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractJohnsonFilter.java:71) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (UrlRewriteFilter.java:738) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (GzipFilter.java:80) (GzipFilter.java:51) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.remoteapps.modules.oauth.OAuth2LOFilter.doFilter(OAuth2LOFilter.java:70)  <+47> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (JWDSendRedirectFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractCachingFilter.java:33) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractEncodingFilter.java:41) (AbstractHttpFilter.java:31) (PathMatchingEncodingFilter.java:49) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ActiveRequestsFilter.java:346) (ActiveRequestsFilter.java:463) (ActiveRequestsFilter.java:173) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (JiraStartupChecklistFilter.java:75) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (MultiTenantServletFilter.java:91) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (StandardWrapperValve.java:233) (StandardContextValve.java:191) (StandardHostValve.java:127) (ErrorReportValve.java:102) (StandardEngineValve.java:109) (AccessLogValve.java:554) (CoyoteAdapter.java:298) (Http11Processor.java:859) (Http11Protocol.java:588) (JIoEndpoint.java:489)
        at java.lang.Thread.run(Thread.java:662)

It might have something to do with a build error I suddenly recieved yesterday when I tried to
reproduce the problem in the devolopment environment on calling "pi" in the atlas-cli console:

[ERROR] Unable to complete running command: pi
java.lang.RuntimeException: org.apache.maven.plugin.MojoExecutionException: Unable to execute mojo
        at org.twdata.maven.cli.commands.ExecuteGoalCommand.run(ExecuteGoalCommand.java:111)
        at org.twdata.maven.cli.commands.ExecuteGoalCommand.run(ExecuteGoalCommand.java:106)
        at org.twdata.maven.cli.CliShell.interpretCommand(CliShell.java:42)
        at org.twdata.maven.cli.CliShell.run(CliShell.java:27)
        at org.twdata.maven.cli.AbstractCliMojo.displayShell(AbstractCliMojo.java:144)
        at org.twdata.maven.cli.AbstractCliMojo.access$000(AbstractCliMojo.java:22)
        at org.twdata.maven.cli.AbstractCliMojo$1.run(AbstractCliMojo.java:116)
Caused by: org.apache.maven.plugin.MojoExecutionException: Unable to execute mojo
        at org.shaded.mojoexecutor.MojoExecutor.executeMojo(MojoExecutor.java:100)
        at org.twdata.maven.cli.MojoCall.run(MojoCall.java:31)
        at org.twdata.maven.cli.commands.ExecuteGoalCommand.runMojo(ExecuteGoalCommand.java:125)
        at org.twdata.maven.cli.commands.ExecuteGoalCommand.run(ExecuteGoalCommand.java:108)
        ... 6 more
Caused by: org.apache.maven.plugin.MojoExecutionException: Unable to execute mojo
        at org.twdata.maven.mojoexecutor.MojoExecutor.executeMojoImpl(MojoExecutor.java:122)
        at org.twdata.maven.mojoexecutor.MojoExecutor$ExecutionEnvironmentM2.executeMojo(MojoExecutor.java:403)
        at org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo(MojoExecutor.java:74)
        at com.atlassian.maven.plugins.amps.MavenGoals.installPlugin(MavenGoals.java:786)
        at com.atlassian.maven.plugins.amps.pdk.InstallMojo.execute(InstallMojo.java:17)
        at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:483)
        at org.shaded.mojoexecutor.MojoExecutor.executeMojo(MojoExecutor.java:98)
        ... 9 more
Caused by: org.apache.maven.plugin.MojoExecutionException: Install Plugin : Upload failed --- {"type":"PLUGIN_INSTALL","status":{"subCode":"upm.plugin.error.unexpected.error","source":"","done":true},"links":{"self":"/jira/rest/plugins/1.0/pending/087c3658-3cc8-4d7f-a4d2-a61b1c38870b"},"timestamp":1343808211611,"username":"admin"}
        at com.atlassian.maven.plugins.pdk.InstallPluginMojo.uploadFile(InstallPluginMojo.java:178)
        at com.atlassian.maven.plugins.pdk.InstallPluginMojo.execute(InstallPluginMojo.java:134)
        at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:483)
        at org.twdata.maven.mojoexecutor.MojoExecutor.executeMojoImpl(MojoExecutor.java:120)
        ... 15 more

So searching for a solution I found this hint:

The problem has been caused by a newer version of the UPM. It failed to parse old audit log entrys, which had been saved in the database as text property in JSON. After purging all audit logs from the database, the problem has been solved.

After running atlas-clean on the development environment (to make sure every possible error entry is gone) I restartet the environment and updated the UPM to 2.5 and suddenly also non-administrators were able to do the license check. But this still doesnt explain what went wrong in the first place.

Digging even a little bit further down, I looked at the code fragment in the ThirdPartyPluginLicenseStorageManagerImpl which throws the PermissionDeniedException and was wondering if there is a scenario in which the first argument "enforceAdmin" would ever be set to true when calling the example license check:

if (enforceAdmin && !hasAdminPermission())
        {
            throw new PluginLicenseStoragePluginPermissionDeniedException(userManager.getRemoteUsername());
        }

How can I be sure that no customer will ever run into this problem without knowing how this permission denied exception could have happened?

Thank you!

Tobias Reibling
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 10, 2012

We are sure that this was caused by the built error and just can hope that this won't repeat.

0 votes
BenW
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
July 30, 2012

Yes, non-administrators should be able to access the plugin license in the above manner. There is probably something else, possibly unrelated, going on. A stacktrace may help to diagnose it.

TAGS
AUG Leaders

Atlassian Community Events