Skip to content

Conversation

josefkarasek
Copy link

@josefkarasek josefkarasek commented Aug 14, 2018

Opening this PR mostly to get feedback. I'll open a new PR against 3.9 and 3.10 ones the fix is ready, with proper grunt build and test.

fixes https://bugzilla.redhat.com/show_bug.cgi?id=1587807

@openshift-ci-robot openshift-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Aug 14, 2018
@josefkarasek josefkarasek requested a review from spadgett August 14, 2018 10:29

var canI = $filter('canI');
var podsLogVersion = APIService.getPreferredVersion('pods/log');
var canViewOperationsLogs = canI(podsLogVersion, 'view');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is checking that you can view the log you're already viewing... @jcantrill Is this really what we want?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This specific issue is that we changed the available index patterns if you are an operations user. You used to get a list of every project in the cluster which was exceedingly long and we modified the seeding to provide only one which matched them all with 'project.*'. The complementary change was not captured in the web console. Operations users are being redirected to Kibana to use an index-pattern which does not exist.

Here we are trying to determine if the use is an operations user by using the same SAR we use in the multi-tenant plugin.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are trying to determine if the use is an operations user by using the same SAR we use in the multi-tenant plugin.

What SAR specifically do you have?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only operations users should be able to view pods/log from the logging project, so:

oc auth can-i view pods/log -n openshift-logging

var archiveUri = function(opts, prefix) {
var archiveUri = function(opts, prefix, canViewOperationsLogs) {
if(canViewOperationsLogs) {
if(!prefix || (prefix && prefix.startsWith('project.'))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two lines can be collapsed into a single if condition


var canI = $filter('canI');
var podsLogVersion = APIService.getPreferredVersion('pods/log');
var canViewOperationsLogs = canI(podsLogVersion, 'view');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spadgett This function is confusing me - the third parameter, project, makes the function behave in a way that I don't understand.

When I run the following code while browsing any project other than openshift-logging, logged in as cluster-admin

canI(podsLogVersion, 'view', 'openshift-logging'');

the function evaluates to false. But when I browse pods/log from openshift-logging project, the function evaluates to true. I'm trying to write something like:

oc adm policy who-can view pods/log -n openshift-logging

and weirdly enough, I get that functionality when I don't specify the project in the function call.
I have to take in consideration that the user is either operations user (who can view project & operations logs) or a regular user.

Any idea how to translate the above oc adm command to a API call? Thank you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need to check a specific permission in another project, you should use SelfSubjectAccessReview

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what the canI filter does under the hood, isn't it?
I'm trying to use its projectName argument, I assume that

AuthorizationService.canI(resource, verb, projectName)

will issue a request against the Authorization API and SSAR is used on the server, or not?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's not what it does... You should run a separate SelfSubjectAccessReview request to check access in another project.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some support for it in the code base?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but it should be pretty easy to call DataService.create with a SelfSubjectAccessReview object:

https://kubernetes.io/docs/reference/access-authn-authz/authorization/#checking-api-access

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the hint I was hoping for, thanks a lot!

@openshift-ci-robot openshift-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Aug 16, 2018
containername: $scope.options.container,
backlink: URI.encode($window.location.href)
}, $filter('annotation')($scope.context.project,'loggingDataPrefix')))
// var ssarVersion = APIService.getPreferredVersion('selfsubjectaccessreviews');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to add SSAR to preferredVersions but somehow this change didn't take effect, even after grunt build.
@spadgett can you advice how to add it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry about adding a preferred version. You'd need to update the origin-web-common repo and cut a release. I don't think it's worth it here.

return data.status.allowed;
}, function() {
return false;
}).then(function(canViewOperationsLogs) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spadgett @jcantrill I'm struggling with the async nature of promises. As this function is not called externally (click on a button etc), at this point log view is blocked. Can you help me how to make sure this promise gets evaluated?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had an issue with my VM, all log files disappeared from the file system. That's why I was seeing weird behavior in the console. The code should be fine.

}
prefix = prefix || 'project.' + opts.namespace + '.' + opts.namespaceUid;
opts.index = prefix + '.*';
console.log('link: ' + opts.index);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will delete once the fix is ready.

}
}
};
var promise = DataService.create('selfsubjectaccessreviews', null, ssar, {namespace: 'openshift-logging'});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure the API version in the request is the same as the endpoint you're calling. I believe it would be

DataService.create({ group: 'authorization.k8s.io', version: 'v1', resource: 'selfsubjectaccessreviews'}, ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be caching this response somewhere so we only check it once per session. You probably want to move this into an Angular service.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if I remove role from a user? That could be a possible danger it that user is logged in a session and has dirty cash.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard, we'll do another round of auth on our side.

@spadgett
Copy link
Member

/cc @jcantrill

Jeff should review as well

@josefkarasek
Copy link
Author

Depends on openshift/origin-web-common#342

@josefkarasek
Copy link
Author

@jcantrill there are still a few issues that need to be resolved

  1. The 'Archive link' button sends a kibana search query[1] in the request's body,
    which is discarded during the oauth process (http 302 redirects remove the body).
    As a result the user lands at default kibana index pattern

  2. The token sent in the request body[1] is ignored by the proxy.
    Oauth proxy can be configured to read Authorization: Bearer: token header.
    Problem in our case is that the web console uses tokens with scope user:info user:check-access,
    but we need user:info user:check-access user:list-projects scope so that Elasticsearch plugin can use this token to check whether the user is operations user.

[1] https://github.com/openshift/origin-web-console/blob/master/app/views/directives/logs/_log-viewer.html#L10-L16

@spadgett
Copy link
Member

If you guys have switched to the OAuth proxy, I don't think we should be sending the token from the console at all anymore, correct?

cc @jwforres

@jwforres
Copy link
Member

the original discussion was the switch to using the oauth proxy was supposed to be transparent to console users and that the existing token mechanism was going to behave the same

the discussion about changing the behavior to stop passing token had been a converged console discussion

@jcantrill
Copy link
Contributor

@jwforres @spadgett I incorrectly was under the impression the oauth-proxy was able to function in the same manor as the original proxy. Pending investigation from @josefkarasek about if it its possible to function in the previous capacity, we may need to revert the proxy being used in order to not have a functional regression. We discussed within the logging team regarding the 4.0 release not having a link from console to kibana which means this work would be uneeded. It means however we need to continue to release the old proxy which I was hoping to avoid

@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch from 6002f80 to 71ccb32 Compare August 29, 2018 11:54
@josefkarasek
Copy link
Author

@jcantrill @spadgett please let me know what you think. I will then update the PR so we can finish this. Thank you

@jcantrill
Copy link
Contributor

@josefkarasek @spadgett this #3067 will resolve the form post/get issue

@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch from 71ccb32 to 3d5fa60 Compare August 29, 2018 16:05
@openshift-ci-robot openshift-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Aug 29, 2018
@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch from b1ab31e to b2e3cdd Compare August 29, 2018 16:51
DataService,
HTMLService,
ModalsService,
AggregatedLoggingService,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not defined in this repo. Please move to this repo per @spadgett request

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's in vendor.js

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are missing the point. The intention is not do any other release of origin-web-common. All the files in 'dist' are generated files that are vendored in through an automated process. The recommendation is o close #342 and move the file to origin-web-console

}, $filter('annotation')($scope.context.project,'loggingDataPrefix')))

var currentUser = AuthService.UserStore().getUser().metadata.name;
AggregatedLoggingService.isOperationsUser(currentUser).then(function(canViewOperationsLogs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be encapsulated this way but I defer to @spadgett. You should be able to simply call:
AggregatedLoggingService.isOperationsUser(currentUser) and assign it to a var. and then pass it in as a param to archiveURI

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be a promise since it makes a selfsubjectaccessreview request to the server, which is asynchronous

'DataService',
'HTMLService',
'ModalsService',
'AggregatedLoggingService',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to keep these alphabetized

// Create SelfSubjectAccessReview request againt authorization API to check whether
// current user can view pods/log from 'openshift-logging' project.
// Users who can view such logs are 'operations' users
var isOperationsUser = function(userName) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not need to take in a user name since it uses self subject access review. (The cached data will be cleared on logout because the page is reloaded, so that's not a problem here.)


var cachedUserPermissions = $cacheFactory('operationsUsersCache', {
number: 10
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like overkill since we are only ever storing one value (if the current user is an operations user)

number: 10
});

var inFlightPermissionsRequest = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed since you should never have multiple in flight requests for this specific permission

// Using cached data.
Logger.log("AggregatedLoggingService, using cached user " + userName);
if ((_.now() - userAllowed.cacheTimestamp) >= 600000) {
userAllowed.forceRefresh = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't worry about forcing refresh... This permission does not change often. Let's just always use the cached value.

if ((_.now() - userAllowed.cacheTimestamp) >= 600000) {
userAllowed.forceRefresh = true;
}
return $q.when(!!_.get(userAllowed, ['allowed']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just...

return $q.when(userAllowed.allowed);

</button>
</form>
<div ng-if="kibanaArchiveUrl">
<a href="{{kibanaArchiveUrl}}" class="btn btn-primary btn-lg">View Archive</a>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ng-href

Why does this have button styling? It should just be a normal link.


var archiveUri = function(opts, prefix) {
var archiveUri = function(opts, prefix, canViewOperationsLogs) {
if((canViewOperationsLogs && !prefix) || (canViewOperationsLogs && prefix && prefix.startsWith('project.'))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (canViewOperationsLogs && (!prefix || prefix.startsWith('project.')) {

@openshift-bot openshift-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Aug 30, 2018
@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch 2 times, most recently from 27f7837 to fc1a1aa Compare August 30, 2018 18:46
@josefkarasek
Copy link
Author

@spadgett are you happy with the latest changes?
If yes, what do we need to do to have this patch merged? This PR is against master, is that ok?
I ran tests against okd 3.10 with latest logging images and they pass.

@jcantrill jcantrill removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 31, 2018
@openshift-ci-robot openshift-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 31, 2018
@jcantrill jcantrill changed the title [WIP] Fix wrong 'archiveLink' for operations user Fix wrong 'archiveLink' for operations user Aug 31, 2018
@openshift-ci-robot openshift-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 31, 2018
null, ssar, {namespace: 'default'}).then(
function(data) {
userAllowed = data.status.allowed;
return Promise.resolve(userAllowed);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return userAllowed;

userAllowed = data.status.allowed;
return Promise.resolve(userAllowed);
}, function() {
return Promise.resolve(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return false;

}
}
};
authPromise = DataService.create({ group: 'authorization.k8s.io', version: 'v1', resource: 'selfsubjectaccessreviews'},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to create a Promise yourself. Just return the Promise from DataService.create

return DataService.create(...).then(...);


var archiveUri = function(opts, prefix) {
var archiveUri = function(opts, prefix, canViewOperationsLogs) {
if((canViewOperationsLogs) && (!prefix || prefix.startsWith('project.'))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: i think the extra parens around canViewOperationsLogs actually make it harder to read

var isOperationsUser = function() {
var authPromise = null;

if (userAllowed === undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd switch this to an early return if we have a cached value. It's easier to reason about.

if (userAllowed !== undefined) {
  return $q.when(userAllowed);
}

var ssar = { ... };
return DataService.create(...).then(...);

@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch 2 times, most recently from cb82403 to 043ed71 Compare August 31, 2018 15:04
@spadgett
Copy link
Member

[FATAL] Built /dist does not match what is committed, run 'grunt build' and include the results in your commit.

Copy link
Member

@spadgett spadgett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but there seems to be a dist mismatch

$scope.$watchGroup(['context.project.metadata.name', 'options.container', 'name'], function() {
angular.extend($scope, {
// The archive URL violates angular's built in same origin policy.
// Need to explicitly tell it to trust this location or it will throw errors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is still needed now that it's a link instead of a form. You can probably get rid of the trustAsResourceUrl call

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is out of date with the code now

return userAllowed;
}, function() {
return false;
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks, this looks much cleaner

@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch from 043ed71 to ef6e11c Compare September 3, 2018 10:47
@josefkarasek
Copy link
Author

@spadgett Thank you for your help and feedback. If there's still something to be done please let me know.

Copy link
Member

@spadgett spadgett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, except please remove the incorrect comment

$scope.$watchGroup(['context.project.metadata.name', 'options.container', 'name'], function() {
angular.extend($scope, {
// The archive URL violates angular's built in same origin policy.
// Need to explicitly tell it to trust this location or it will throw errors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is out of date with the code now

// The archive URL violates angular's built in same origin policy.
// Need to explicitly tell it to trust this location or it will throw errors.
kibanaArchiveUrl: logLinks.archiveUri({
baseURL: url,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what's wrong with indentation here - a new block of code - indented by 2 spaces against its parent block

@josefkarasek josefkarasek force-pushed the bz1587807-archive-link branch from ef6e11c to 40e9714 Compare September 4, 2018 14:38
Copy link
Member

@spadgett spadgett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

Thanks @josefkarasek 👍

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Sep 4, 2018
@openshift-merge-robot openshift-merge-robot merged commit 926f65e into openshift:master Sep 4, 2018
@jcantrill
Copy link
Contributor

/cherrypick release-3.10

@openshift-cherrypick-robot

@jcantrill: #3060 failed to apply on top of branch "release-3.10":

error: Failed to merge in the changes.
Using index info to reconstruct a base tree...
M	app/index.html
M	app/scripts/directives/logViewer.js
M	app/scripts/services/logLinks.js
M	app/views/directives/logs/_log-viewer.html
M	dist/scripts/scripts.js
M	dist/scripts/templates.js
M	dist/scripts/vendor.js
Falling back to patching base and 3-way merge...
Auto-merging dist/scripts/vendor.js
Auto-merging dist/scripts/templates.js
Auto-merging dist/scripts/scripts.js
CONFLICT (content): Merge conflict in dist/scripts/scripts.js
Auto-merging app/views/directives/logs/_log-viewer.html
Auto-merging app/scripts/services/logLinks.js
Auto-merging app/scripts/directives/logViewer.js
CONFLICT (content): Merge conflict in app/scripts/directives/logViewer.js
Auto-merging app/index.html
Patch failed at 0001 Fix wrong 'archiveLink' for operations user

In response to this:

/cherrypick release-3.10

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@jcantrill
Copy link
Contributor

@josefkarasek please backport to 3.10 and 3.9 to fix relevent issues

@spadgett
Copy link
Member

spadgett commented Sep 4, 2018

Note that this will need some rework if we aren't using oauth proxy in 3.10 and 3.9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants