go to post Daniel Kutac · May 11, 2020 Hello Nagarjuna, IAM run on InterSystems IRIS Data Platform 2019.2 and higher. You need to upgrade your server. Once you're done, you would find everything (the /api/iam application , IAM user) in the System Management Portal. HTH Dan
go to post Daniel Kutac · Feb 11, 2020 You can also check this link for SOAP debugging - https://community.intersystems.com/post/iscsoap-error-console-log. the first reply in the article points to documentation about SOAP LOG feature - this allows you to record SOAP traffic into a file with all details. Dan
go to post Daniel Kutac · Feb 10, 2020 it turned out to be access privileges issue with license file, what a silly mistake of mine. Anyway, thank you Evgeny for pointing me to some useful info, anyway!
go to post Daniel Kutac · Sep 24, 2019 Sebastien, I remember once customer had the same problem and it turned out that they had large amount of cached queries existent in that namespace. Can you check and eventually delete them? Other than this, I can imagine some issues with source control if you have any, but this is just a guess. HTH Dan
go to post Daniel Kutac · Jul 31, 2019 Zdenek, following up with our offline conversation, I made small change to my installer manifest, so PerformUpgrade() method contains something like this: s ^dk="Upgrade to version "_..#VERSION_" performed OK" s ^dk("aux")=pAux s ^dk("MYVAR")=$System.Util.GetEnviron("MYVAR") // a nyni muzeme volat kod v manifestu, a nebo taky ne a vse muzeme provest rovnou v teto metode set pVars("IsUpgrade")=1 set pVars("AppVersion")=..#VERSION set tSC=..setup(.pVars,3) return tSCmy simple installer script (CentOS7) - that I sent you offline - needs no changes, but before I call it, I do this:[root@localhost install-scripts]# export MYVAR="kutac"[root@localhost install-scripts]# echo $MYVARkutac[root@localhost install-scripts]# ./silent-setup.sh 1about to run only upgradethen, looking at %SYS namespace what comes into ^dk global:[root@localhost ~]# csession ens1Node: localhost.localdomain, Instance: ENS1Username: rootPassword: ********USER>zn "%sys"%SYS>zw ^dk^dk="Upgrade to version 1.2 performed OK"^dk("MYVAR")="kutac"^dk("aux")="toto je test"%SYS> --- as you can see, it works just fine. perhaps your problems are due to security / permissions rather then anything else.feel free to contact me directly.Dan
go to post Daniel Kutac · May 9, 2019 So, at the end I found the answer and I'm going to share it with the audience, in case someone may have the same issue.But before I provide code, a few more words about SOAP service. The SOAP service has just one method - Test. It accepts a string and returns another string. That's it. I then created a WS Policy via Wizard, this policy is using SAML Authorization with X.509 Certificates. (no ws addressing, no body / token protection, and recipient token using X.509 credentials to keep my example simple)I then generated a SOAP client, based on WSDL produced by the above service.and here is the code: Class WSC.ClientTest Extends %RegisteredObject { /// d ##class(WSC.ClientTest).Run(2) ClassMethod Run(pValue As %String = 0) { set tClient=##class(WSC.SecureDemo.MySecuredServiceSoap).%New() set tClient.SSLConfiguration="SELF-MASTER" /******************************************************************* In real life, we would retrieve a SAML Assertion token from an IDENTITY PROVIDER - IdP - and just pass it to the web service. The WebService (SERVICE PROVIDER / SeP) (unauthenticated or using a technical account on Cache server side) would need to retrieve the SAML Assertion from SOAP Header and perform its validation *******************************************************************/ // !!! PLEASE REMEMBER TO DELETE A WS-POLICY CONFIGURATION GENERATED FOR WS CLIENT! /*********************************************************** * This is a dummy code to construct a SAML token... * ***********************************************************/ set tCred = ##class(%SYS.X509Credentials).GetByAlias("SAML-DEMO","norway01") // Create the SAML Assertion token object - this is just a form of X509 certificate #dim tSamlAssertion As %SAML.Assertion = ##class(%SAML.Assertion).CreateX509(tCred) set tSamlAssertion.IssueInstant = $zdt($h,3,,3) // in real life we would receive this data from IdP !!! #dim tName As %SAML.NameID = ##class(%SAML.NameID).%New() set tName.NameID = "https://DESKTOP-Q224QPV" // saml token issuer, in this case it's me, my computer :) set tSamlAssertion.Issuer = tName set tSub = ##class(%SAML.Subject).%New() #dim tName2 As %SAML.NameID = ##class(%SAML.NameID).%New() set tName2.NameID = "daniel.kutac@intersystems.com" set tSub.NameID = tName2 set tSamlAssertion.Subject = tSub #dim tAuthSt As %SAML.AuthnStatement = ##class(%SAML.AuthnStatement).%New() set tAuthSt.AuthnInstant = $zdt($h,3,,3) // SAML conditions - make sure SAML token is not valid too long... set tNow=$h set tConditions=##class(%SAML.Conditions).%New() set tConditions.NotBefore=$zd($p(tNow,",",1),3)_" "_$zt(($p(tNow,",",2)-30),1) set tConditions.NotOnOrAfter=$zd($p(tNow,",",1),3)_" "_$zt(($p(tNow,",",2)+900),1) set tSamlAssertion.Conditions=tConditions // Attribute statements #define AddAttribute(%key,%value,%nf) set tAttribute = ##class(%SAML.Attribute).%New() ##continue set tAttribute.Name=%key ##continue set tAttributeValue = ##class(%SAML.AttributeValue).%New() ##continue set tAttribute.NameFormat = %nf ##continue do tAttribute.AttributeValue.Insert(tAttributeValue) ##continue do tAttributeStatement.Attribute.Insert(tAttribute) #define AddStringAttribute(%key,%value,%nf) $$$AddAttribute(%key,%value,%nf) Do tAttributeValue.SetString(%value) #define AddElementAttribute(%key,%value,%nf) $$$AddAttribute(%key,%value,%nf) Do tAttributeValue.SetElement(%value) set tAttributeStatement=##class(%SAML.AttributeStatement).%New() $$$AddStringAttribute("name","Daniel Kutac","") $$$AddStringAttribute("network_id","kutac","") $$$AddStringAttribute("division","Sales Organization","") do tSamlAssertion.Statement.Insert(tAttributeStatement) /************************************ * End SAML Assertion data * ************************************/ // add SAML Token to SOAP Header do tClient.SecurityOut.AddToken(tSamlAssertion) // add WS timeStamp, this is needed by WS Security policy set tTS=##class(%SOAP.Security.Timestamp).Create() do tClient.SecurityOut.AddSecurityElement(tTS) // this would be, in real life, a technical account, or even unauthenticated CSP application set tUToken=##class(%SOAP.Security.UsernameToken).Create("kutac","xxx") do tClient.SecurityOut.AddSecurityElement(tUToken) // response has - per policy - signed body, we only display result, if signature is valid #dim e as %Exception.AbstractException try { write !," result: ",tClient.Test(pValue) } catch (e) { if $ZERROR["<ZSOAP>" { w !,"SOAP FAULT ERROR:",! d $System.OBJ.DisplayError(%objlasterror) } else { w !,"Other error:",!,e.DisplayString() } } } one more comment: you may need to implement OnPreWebMethod() method in the SOAP service where you validate incoming SAML assertion token.
go to post Daniel Kutac · Apr 24, 2019 Hello Muhammad,first of all, I'm not able to give you a complete answer, but hope to have some thoughts that may help you.I'm not an angular nor web developer either, so I have to trust Google, too. According to others (Google) it is indeed difficult to secure information in browser's storage. Besides suggestions like using sessionStorage instead of localStorage, not letting other people to come to your PC and use your open session or ultimately, requiring authentication before each call to resource server, perhaps it might make a sense to pass, together with access token, another parameter in the header, that would change between requests in an exact manner that only resource server and your client know (client using code encapsulation to make it difficult for attacker to find in external files).Storing access code at the web server app means that you'd need to add to you angular client also something like CSP application or some other server side application. this would make things more complicated to maintain.Dan
go to post Daniel Kutac · Dec 13, 2018 Hello Julie,AFAIK there is no intelligence in operation's message queue other than First came - first served.You need to build the logic yourself. Having separate operations for large and small messages / priorities is a good starting point. You can then use poolSize setting to play with priority of processing (bigger poolSize means "usually" larger throughput.)Dan
go to post Daniel Kutac · Jul 13, 2018 This approach has an advantage over usign %GSIZE as the query in %SYS.GlobalQuery class has a parameter that can make quick estimations of the global sizes (simply counting # of blocks occupied by globals) rather than potentialy very slow exact global size determination always used by %GSIZE
go to post Daniel Kutac · Dec 27, 2017 Soufiane,supposing you have successfully been able to add the token to your client (this depends on ate respective framework) call for Cache resources (via REST API), then on Cache side, if that's where your data (resources) are sitting, you can use something like this:set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.tSC) // decode token data into JSON object $$$THROWONERROR(tSC,##class(%SYS.OAuth2.AccessToken).GetIntrospection($$$APP,accessToken,.jsonObjectAT)) /* service specific check */ // check whether the request is asking for proper scope for this service if '(jsonObjectAT.scope["special-deals") set reason=..#HTTP404NOTFOUND throw /* finally */ // validate signed access token (JWT) if '(##class(%SYS.OAuth2.Validation).ValidateJWT($$$APP,accessToken,,,.jsonObjectJWT,.securityParameters,.tSC)) { set reason=..#HTTP401UNAUTHORIZED $$$ThrowOnError(tSC) } perhaps you shall try to look at this post - https://community.intersystems.com/post/angular-client-demo-using-oauth2-authorization-server-protect-caché-based-resources, it also contains a link to the angular based project and contains implementation of sample Cache REST service. Dan
go to post Daniel Kutac · Dec 13, 2017 I think grant types are not used by he resource server, only by Confidential and Public clients.
go to post Daniel Kutac · Nov 14, 2017 Soufiane,briefly, perhaps not 100% correctly - use Google for more details, claims are characteristics provided by OIDC (OpenID Connect) server that describe authenticated user. e.g. Caché by default supports these claims (and more):preferred_username, email, email_verified, name, phone_number, phone_number_verified, iss, sub, aud, exp, auth_time, ...claims can be used by the access_token to provide additional information about the user passed to the resource server when calling REST method. Some claims are mandatory, some are optional. You can provide optional claims by the SetClaimValue() method.Dan
go to post Daniel Kutac · Oct 12, 2017 Hi Praveen,this is not going to be an exhausting answer but rather a summary of choices you have.First thing to answer: are you working with a legacy application, that stored data in globals, not using our Cache persistent classes? In this case, you would like to follow Sean's globals to classes mapping guide.Another option, suitable in cases where you have a mix of persistent classes and only some data stored directly in globals, you may consider using custom SQL queries. In such query you implement code that iterates over your global nodes and expose result as SQL resultset. You can then call query as a standard stored procedure. see Cache online reference for mode details here.There is one more option too, which could be used in some special cases when global is a simple structure. In such case you could create a new persistent class definition and simply override the storage generated during its compilation to reflect your global structure. This is less flexible than using SQL mapping mentioned as first choice, but could be easier for you.HTH
go to post Daniel Kutac · Sep 20, 2017 there is an easy solution to your issue. Simply use a Cache Task Manager. Create a new task, and within code, instantiate Ensemble service Ens.Director,e.g. Set tSC=##class(Ens.Director).CreateBusinessService("your service configration name",.tService) If ($$$ISERR(tSC)) QuitSet tSC=tService.ProcessInput(%request,.output)If ($$$ISERR(tSC)) QuitIf $IsObject($G(output)) { // do whatever you want here}
go to post Daniel Kutac · Jul 18, 2017 Noone would give you exact numbers. It really depends on your use case.However, adding 200 properties to an Ensemble message (not considering other classes as you pass just messages) may either simp0ly mean that you add 200 properties to ONE class or to MANY classes, depending how clever the original design of your production was.You may, or with the same probability many not, need to change the message design and switch to virtual documents ... it really depends on many factors unique to your particular use case - throughput expected, load of data incoming etc etc...
go to post Daniel Kutac · Jul 14, 2017 Jose, $lb() holds STORED values of you object instance. If your opened instance modified property(ies) then I see no point of looking into stored data, just serialize you IN-MEMORY values to JSON.On the other hand, if a process A opened and modified instance of the object and without saving and you want to serialize the same instance from process B, then again, there is no difference between opening an object instance or using some custom serialization directly from stored data.It is not good practice anyway to keep objects opened for a long time without saving their new values.lastly, my comment about JSON array was that JSON array doesn't need to know the name in the name:value pair so you can easily write a custom JSON serializer to serialize directly $lb() into JSON array. maybe I missed your original business case need, can you explain why current implementation is not good enough for you?
go to post Daniel Kutac · Jul 14, 2017 Jose,how would you determine names of properties / keys for a JSON name:value pairs without opening an object instance or retrieving those names from somewhere else?or are you happy to express it as JSON ARRAY ?
go to post Daniel Kutac · Jul 12, 2017 I work with Cache for decades and never knew about ExtentFunc(). There is always something to learn...Mike, in Studio use Show Other View to display the generated INT code for the Sample. Employee class. You'll find the ExtentFunc() there. You may need to compile the Sample.Employee class first to re-generate the INT code.
go to post Daniel Kutac · May 30, 2017 Safeena,you do not invoke web methods directly. You need to create a client class by consuming a WSDL file that your service exposes. There is a wizard that guides you through the process of client creation. Apart to client class itself the wizard also generates all data types used by a web service. Please consult documentation here.There are some other option when using Ensemble but I suggest you follow the link above.
go to post Daniel Kutac · Mar 15, 2017 Thomas,Hope I understood your question correctly, if not then let me know.In general, when dealing with XML VDoc documents (files), you need to create a production that uses services based onEnsLib.EDI.XML.Service.FileService, operations based on EnsLib.EDI.XML.Operation.FileOperation and a routing process - EnsLib.MsgRouter.VDocRoutingEngine. There is no need to do any coding, just supply parameters in the production diagram.You may need to provide DocSchemaCategory setting for a service, for this, you need to import the XML Schema, using Import button at Ensemble->Interopeate->XML->XML Schema Structures page.for actual routing, you need to design a rule, and supply path to the document element/attribute that's used to decide where the rule sends document to. I prefer using XPATH expressions for this.An example of routing rule contents is here:<ruleDefinition alias="" context="EnsLib.MsgRouter.VDocRoutingEngine" production="tzp.dasta.router.Production"><ruleSet name="" effectiveBegin="" effectiveEnd=""><trace value="Document.{/dasta/is/ip/lo/loi/@material}"></trace><rule name=""><constraint name="source" value="Dasta3Zadanka"></constraint><constraint name="msgClass" value="EnsLib.EDI.XML.Document"></constraint><constraint name="docCategory" value="ds030101"></constraint><when condition="Document.{/dasta/is/ip/lo/loi/@material}="B""><send transform="" target="Dasta3Biochemie"></send><return></return></when><otherwise><send transform="" target="Dasta3Mikrobiologie"></send><return></return></otherwise></rule></ruleSet></ruleDefinition>You can create a VDOC document from a persistent (any, not only persistent) object, as long as it extends also from %XML.Adaptor. First, you serialize your object instance to XML stream or string, and then using ImportFromString/ImportFromLibraryStream (or other - see online reference for EnsLib.EDI.XML.Document class) method you instantiate a VDoc document.HTH.Dan