Prevent access to oracle datasource credentials from reportexplorer control how

Posted by: mschmitz on 4 April 2018, 12:06 pm EST

    • Post Options:
    • Link

    Posted 4 April 2018, 12:06 pm EST - Updated 30 September 2022, 9:22 am EST

    Hello I’m trying to have active report’s reportdesigner load in such a way where the oracle credentials are passed into the report behind the scenes. I put in code to set up the oracle data source with the connection string after the report loads. I would like to have the credentials inaccessible to the user from the report designer.

    At the moment all a user has to do is right click on the data source, edit data source, and click on the connection string tab and they can see the username and password which I would like to keep hidden from the user.

    The closest thing I’ve found to do what I need it to do is from the reportexplorer’s VisibleNodes property. With that I can remove the datasource node from the reportexplorer entirely but it also removes the fields too which I think I would want. I’d like to be allow them to create datasets too.

    Some ideas I’ve had are:

    Anything that can hide the data source while still keeping its data fields visible in the report explorer?

    Anything that can remove the users ability to have access to the right click menu when clicking on the data source?

    Something to disable the option to edit a data source?

    Something to disable the connection string tab in the data source dialogue box?

    Something that can allow for access to the database to preview a report without letting a users see credentials? Populating the credentials of the data source for only a moment when the previewkeydown event occurred to me but can’t get that to fire. Adding code in other events of the reportexplorer control hasn’t worked either.

  • Posted 5 April 2018, 5:42 am EST

    The only way to hide the credentials from your users is to use the VisibleNodes property of the ReportExplorer. However, since you wish to keep the data fields visible, it is not possible to use the VisibleNodes property. The only other way is to provide the credentials for the datasource in code because even if we somehow hide the datasource node, the credentials will still be stored in the report and can be viewed by opening the Report file (rdlx) in a TextEditor. Hope it is helpful

  • Posted 5 April 2018, 10:27 am EST

    I was aware of the issue with being able to open the report file in a text editor too. What I do for that is populate the datasource connection string after the report loads and if the try to save the report I clear it. I just need a hack or something to stop them from being able to get to that data source dialogue window or disable that tab to the connection string

  • Posted 9 April 2018, 12:13 am EST

    There’s no hack that I could find to prevent the datasource dialog from showing or to disable the connectionstring tab. Let me get in touch with my peers and find if there is any possible solution. (Tracking id - 256854)

  • Posted 9 April 2018, 1:49 am EST - Updated 30 September 2022, 9:22 am EST

    I’m exploring api calls to disable the windows or tab. Using the FindWindow function to get the window handle and enablewindow function to disable it. Something like that might work

    [DllImport(“user32.dll”)]

    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport(“user32.dll”, SetLastError = true)]

    static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

    [DllImport(“user32.dll”)]

    [return: MarshalAs(UnmanagedType.Bool)]

    static extern bool EnableWindow(IntPtr hWnd, bool bEnable);

    IntPtr hwndWindow = FindWindow(“WindowsForms10.Window.8.app.0.1f8395f_r14_ad1”, “Report Data Source - General”);

    IntPtr hwndControl = FindWindowEx((IntPtr)hwndWindow, IntPtr.Zero, “WindowsForms10.Window.8.app.0.1f8395f_r14_ad1”, “Connection String”);

    if (EnableWindow(hwndcontrol, false))

    {

    //has been disabled

    }

  • Posted 9 April 2018, 7:25 am EST

    I kind of got the credentials inaccessible to the user in a clunky way with the api calls. I couldn’t get the FindWindowEx to see the edit datasource window during the execution of any of the events in the reportExplorer from it being a model window.

    I put in a timer running every tenth of a second that continuously checks for the window coming up and disables the contents of the window except for the “ok” and “cancel” buttons.

        private void timer1_Tick(object sender, EventArgs e)
        {
           // return;
            IntPtr hwndWindow = FindWindow(GetClassNameOfWindow(thiswindow), "Report Data Source - General");
            IntPtr hchild = IntPtr.Zero;
            if (!hwndWindow.Equals(IntPtr.Zero) )
            {
                IntPtr hwndControl = FindWindowEx(hwndWindow, IntPtr.Zero, GetClassNameOfWindow(thiswindow), "");
    
                if (!hwndControl.Equals(IntPtr.Zero))
                {
                    if (EnableWindow(hwndControl, false))
                    {
                        //has been disabled
                    }  
    
                }
                
            } 
        }
    

    and have the timer turned on when the reportExplorer gets focus and turn the timer off when reportExplorer loses focus so it does not need to run all the time.

        private void reportExplorer_Enter(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }
    
        private void reportExplorer_Leave(object sender, EventArgs e)
        {
            timer1.Enabled = false;
        }
    

    Not the preferred solution though

  • Posted 9 April 2018, 5:33 pm EST

    I have good news for you. There is a solution to prevent the users from opening the DataSource dialog. You can handle the reportExplorer’s SelectionChanged event as below:

    reportExplorer.SelectionChanged += ReportExplorer_SelectionChanged;
    
    private void ReportExplorer_SelectionChanged()
            {
                try
                {
                    var tv = reportExplorer.Controls[0].Controls[0] as TreeView;
                    tv.Nodes[0].Nodes[1].Tag = tv.Nodes[0].Nodes[0].Tag;
    
                    foreach (TreeNode _dc in tv.Nodes[0].Nodes[1].Nodes)
                    {
                        _dc.Tag = tv.Nodes[0].Nodes[0].Tag;
                    }
                }
    
                catch { }
            }
    

    Hope this helps

  • Posted 10 April 2018, 4:00 am EST - Updated 30 September 2022, 9:22 am EST

    Thanks that was helpful. It does prevent the user from getting into the datasource dialogue window but there’s some other change in behavior that makes it more difficult to create data sets

    I tested the way the right click menu and “add button” in the reportexplorer behaved before and after this change. (see above screenshot)

    It doesn’t let me add a data source when I right click on the data source with the right click no longer producing a menu. The option to create a dataset when clicking on the “add button” while a datasource is also removed when this change is applied. But it is still possible to create a dataset by clicking on a pre-existing dataset and then clicking the “add button” so at least its still possible to create a dataset. But if there’s a way to make the other ways work too that would be nice.

    The other issue with creating a dataset is that after creating one with this change in place it does not show the new dataset node in the reportexplorer control. But if save the report and reload it then it shows. That is something else I had to do to get the reportexplorer to refresh itself after adding items to it through code. By adding this code in the load event procedure:

            MemoryStream stream = new System.IO.MemoryStream();
            System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(stream);
            ((PageReport)(reportDesigner.Report)).Save(writer);
            writer.Flush();
            stream.Position = 0;
    
            System.Xml.XmlReader reader = System.Xml.XmlReader.Create(stream);
            reportDesigner.LoadReport(reader, DesignerReportType.Page);            
    

    But saving/reloading the report, wouldn’t work well when adding items during runtime while the user is the middle of creating a report. You know of another way to fresh this control?

  • Posted 11 April 2018, 12:17 am EST

    The behavior after using the code above is correct, since right click is prevented. You can add a datasource and a dataset from the Add button at the top. But I’ll get in touch with the concerned team regarding the DataSet appearing after re-loading the report and get back to you.

  • Posted 15 April 2018, 11:44 am EST

    This does it

        private void reportExplorer_Leave(object sender, EventArgs e)
        {
            this.reportExplorer.ReportDesigner = this.reportDesigner; 
            
        }
    

    Except they have to click outside of the ReportExplorer before it’ll refresh itself. I tried putting it in other places but haven’t had luck getting it to refresh the moment they make a change without having to get the user to do something else afterward before it refreshes.

  • Posted 15 April 2018, 4:48 pm EST

    I’m discussing this further with my peers on how to get this working and will get back to you.

  • Posted 15 April 2018, 11:31 pm EST

    Here’s a little more complex implementation of your requirement to prevent users from opening the DataSource dialog and also be able to add DataSets.

    private void OnLayoutChanged(object sender, LayoutChangedArgs e)
            {
                if (e.Type == LayoutChangeType.ReportLoad || e.Type == LayoutChangeType.ReportClear)
                {
                    needs_refresh = true;
                }
                if (e.Type == LayoutChangeType.ReportClear)
                {
                    _reportName = null;
                }
                if (e.Type == LayoutChangeType.ReportLoad)
                {
                    if (!string.IsNullOrEmpty(_reportName))
                    {
                        if (GetIsMaster())
                        {
                            _reportName = null;
                        }
                    }
                }
                SetTitle();
            }
    
            private object ds_tag = null;
            private bool needs_refresh = false;
    
            private void EndUserDesigner_Load(object sender, EventArgs e)
            {
    
                var tv = reportExplorer.Controls[0].Controls[0] as TreeView;
                ds_tag = tv.Nodes[0].Nodes[1].Tag;
                tv.Nodes[0].Nodes[1].Tag = tv.Nodes[0].Nodes[0].Tag;            
                tv.MouseDown += tv_MouseDown;
    
                var ts = reportExplorer.Controls[1] as ToolStrip;
                (ts.Items[0] as ToolStripDropDownButton).Click += EndUserDesigner_Click;
    
                foreach (ToolStripDropDownItem ddi in (ts.Items[0] as ToolStripDropDownButton).DropDownItems)
                {
                    System.Diagnostics.Debug.WriteLine(ddi.Name);
    
                    if (ddi.Name == "addDataSourceToolStripMenuItem")
                    {
                        ddi.Enabled = false;
                        ddi.EnabledChanged += ddi_EnabledChanged;
                    }
                }
    
                foreach (ToolStripItem tsi in ts.Items)
                {
                    if (tsi.Name.Contains("Delete"))
                    {
                        tsi.Click+=tsi_Click;
                    }
                }
            }
    
    
            void ddi_EnabledChanged(object sender, EventArgs e)
            {
                (sender as ToolStripDropDownItem).Enabled = false;
            }
    
            void tsi_Click(object sender, EventArgs e)
            {
                this.reportExplorer.ReportDesigner = this.reportDesigner; 
            }
    
            void tsi_EnabledChanged(object sender, EventArgs e)
            {
                (sender as ToolStripItem).Enabled = false;
            }
    
            void tv_MouseDown(object sender, MouseEventArgs e)
            {
                ResetTag();
                try
                {
                    var tv = reportExplorer.Controls[0].Controls[0] as TreeView;
                    tv.Nodes[0].Nodes[1].Tag = tv.Nodes[0].Nodes[0].Tag;
    
                    foreach (TreeNode _dc in tv.Nodes[0].Nodes[1].Nodes)
                    {
                        _dc.Tag = tv.Nodes[0].Nodes[0].Tag;
                    }
                }
                catch { }
            }
    
            private void reportExplorer_SelectionChanged()
            {
                var tv = reportExplorer.Controls[0].Controls[0] as TreeView;
                try
                {
                    if (!tv.InvokeRequired)
                    {
                        if (tv.SelectedNode != null)
                        {
                            if (tv.SelectedNode.Parent != null)
                            {
                                if (tv.SelectedNode.Parent.Text == "Data Sources")
                                {
                                    var ts = reportExplorer.Controls[1] as ToolStrip;
                                    foreach (ToolStripItem tsi in ts.Items)
                                    {
                                        if (tsi.Name == "tsbEdit" || tsi.Name.Contains("Share") || tsi.Name.Contains("Delete"))
                                        {
                                            tsi.Enabled = false;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
    
            void EndUserDesigner_Click(object sender, EventArgs e)
            {
                ResetTag();
            }
    
            private void ResetTag()
            {
                var tv = reportExplorer.Controls[0].Controls[0] as TreeView;
                if (needs_refresh)
                {
                    needs_refresh = false;
                    ds_tag = tv.Nodes[0].Nodes[1].Tag;
                }
                else
                {
                    tv.Nodes[0].Nodes[1].Tag = ds_tag;
                }
            }
    

    I have attached a sample as well with the above implementation. It’s a modified version of the default EndUserDesigner demo.

    EndUserDesigner_PreventDataSourceEdit.zip

  • Posted 16 April 2018, 3:00 am EST

    Thanks, it looks well done to me :slight_smile: I’ve been testing it out. I think it’s doing everything we would need it to do.

  • Posted 17 April 2018, 1:03 am EST

    Great. Glad to know the code is of help and is doing everything you’re looking for.

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels